private void SetCustomAnim(CustomAnimationData customAnim, Vector2 dir)
    {
        toggledCustomAnim = false;

        currentCustomAnim   = customAnim;
        customAnimStartTime = Time.time;
        customAnimStartDir  = dir;
        customAnimStartPos  = Character.mainShells.transform.position.xz();
    }
    private static void MergeMesh(GameObject go, AnimationClip clip)
    {
        //AnimationClipSettings setting = AnimationUtility.GetAnimationClipSettings(clip);
        //if (!setting.loopTime)
        //{
        //    return;
        //}
        AnimationClip copyClip = Object.Instantiate(clip);
        GameObject    copyGo   = Object.Instantiate(go);

        EditorCurveBinding[] bindings = AnimationUtility.GetCurveBindings(copyClip);
        m_aniData.Clear();

        //存储动画数据,为后续检查做准备
        for (int i = 0; i < bindings.Length; i++)
        {
            AnimationCurve      curve = AnimationUtility.GetEditorCurve(copyClip, bindings[i]);
            CustomAnimationData caData;
            if (!m_aniData.TryGetValue(bindings[i].path, out caData))
            {
                caData = new CustomAnimationData();
                m_aniData.Add(bindings[i].path, caData);
            }
            if (bindings[i].propertyName.ToLower().Contains("scale.x"))
            {
                caData.BindScale[0]  = bindings[i];
                caData.CurveScale[0] = curve;
            }
            else if (bindings[i].propertyName.ToLower().Contains("scale.y"))
            {
                caData.BindScale[1]  = bindings[i];
                caData.CurveScale[1] = curve;
            }
            else if (bindings[i].propertyName.ToLower().Contains("scale.z"))
            {
                caData.BindScale[2]  = bindings[i];
                caData.CurveScale[2] = curve;
            }
            else if (bindings[i].propertyName.ToLower().Contains("position.x"))
            {
                caData.BindPosition[0]  = bindings[i];
                caData.CurvePosition[0] = curve;
            }
            else if (bindings[i].propertyName.ToLower().Contains("position.y"))
            {
                caData.BindPosition[1]  = bindings[i];
                caData.CurvePosition[1] = curve;
            }
            else if (bindings[i].propertyName.ToLower().Contains("position.z"))
            {
                caData.BindPosition[2]  = bindings[i];
                caData.CurvePosition[2] = curve;
            }
            else if (bindings[i].propertyName.ToLower().Contains("rotation.x"))
            {
                caData.BindRotation[0]  = bindings[i];
                caData.CurveRotation[0] = curve;
            }
            else if (bindings[i].propertyName.ToLower().Contains("rotation.y"))
            {
                caData.BindRotation[1]  = bindings[i];
                caData.CurveRotation[1] = curve;
            }
            else if (bindings[i].propertyName.ToLower().Contains("rotation.z"))
            {
                caData.BindRotation[2]  = bindings[i];
                caData.CurveRotation[2] = curve;
            }
            else if (bindings[i].propertyName.ToLower().Contains("rotation.w"))
            {
                caData.BindRotation[3]  = bindings[i];
                caData.CurveRotation[3] = curve;
            }
        }
        //检查是否可以删除curve,可以的话就删除
        foreach (KeyValuePair <string, CustomAnimationData> item in m_aniData)
        {
            item.Value.DoCheck();
        }
        //如果父节点有动画,则子节点不能合并的
        foreach (KeyValuePair <string, CustomAnimationData> item in m_aniData)
        {
            item.Value.CanRemove = IsNodeCanRemove(item.Key, item.Value.CanRemove);
        }
        //删除curve
        foreach (KeyValuePair <string, CustomAnimationData> item in m_aniData)
        {
            if (item.Value.CanRemove)
            {
                for (int i = 0; i < item.Value.BindPosition.Length; i++)
                {
                    if (null != item.Value.BindPosition[i] &&
                        !string.IsNullOrEmpty(item.Value.BindPosition[i].path))
                    {
                        AnimationUtility.SetEditorCurve(copyClip, item.Value.BindPosition[i], null);
                    }
                }
                for (int i = 0; i < item.Value.BindScale.Length; i++)
                {
                    if (null != item.Value.BindScale[i] &&
                        !string.IsNullOrEmpty(item.Value.BindScale[i].path))
                    {
                        AnimationUtility.SetEditorCurve(copyClip, item.Value.BindScale[i], null);
                    }
                }
                for (int i = 0; i < item.Value.BindRotation.Length; i++)
                {
                    if (null != item.Value.BindRotation[i] &&
                        !string.IsNullOrEmpty(item.Value.BindRotation[i].path))
                    {
                        AnimationUtility.SetEditorCurve(copyClip, item.Value.BindRotation[i], null);
                    }
                }
            }
        }

        //遍历可以删除的path,在go上找出来,设置key的值,并将这些网格合并
        //TODO:暂时不处理材质不同的情况,默认go下所有材质都是同一个。
        Material          sharedMat    = null;
        List <MeshFilter> filterList   = new List <MeshFilter>(); //用于合并的
        List <Transform>  childrenList = new List <Transform>();  //待删除的

        //所有被删除了curve的,加入到待删除列表和合并列表
        foreach (KeyValuePair <string, CustomAnimationData> item in m_aniData)
        {
            Transform child = copyGo.transform.Find(item.Key);
            if (null == child)
            {
                Debug.LogError("can not find " + item.Key + " in " + copyGo.name);
                continue;
            }
            if (!item.Value.CanRemove)
            {
                continue;
            }

            MeshFilter childFilter = child.GetComponent <MeshFilter>();
            if (null == childFilter)
            {
                continue;
            }
            if (item.Value.SignScale)
            {
                child.localScale = item.Value.Scale;
            }
            if (item.Value.SignPosition)
            {
                child.localPosition = item.Value.Position;
            }
            if (item.Value.SignRotation)
            {
                child.localRotation = item.Value.Rotation;
            }

            if (null == sharedMat)
            {
                MeshRenderer render = child.GetComponent <MeshRenderer>();
                if (null != render)
                {
                    sharedMat = render.sharedMaterial;
                }
            }
            else
            {
                MeshRenderer render = child.GetComponent <MeshRenderer>();
                if (null != render && sharedMat != render.sharedMaterial)
                {
                    Debug.LogError(copyGo.name + "存在两个以上的材质球,会导致合并错误。");
                    continue;
                }
            }

            childrenList.Add(child);
            filterList.Add(childFilter);
        }
        //找出所有原来就没有k帧的child
        List <Transform> tempList = new List <Transform>();

        FindNoAnimationChildren(copyGo.transform, copyGo.transform, tempList);
        for (int i = 0; i < tempList.Count; i++)
        {
            MeshRenderer mr = tempList[i].GetComponent <MeshRenderer>();
            if (mr == null)
            {
                continue;
            }
            if (sharedMat == null)
            {
                sharedMat = mr.sharedMaterial;
            }
            if (mr.sharedMaterial == sharedMat)
            {
                childrenList.Add(tempList[i]);
                filterList.Add(tempList[i].GetComponent <MeshFilter>());
            }
            else
            {
                Debug.LogError(tempList[i].name + "有不一样的材质");
                //
                if (tempList[i].transform.lossyScale.x <= 0.012f &&
                    tempList[i].transform.lossyScale.y <= 0.012f &&
                    tempList[i].transform.lossyScale.z <= 0.012f)
                {
                    childrenList.Add(tempList[i]);
                }
            }
        }
        //去掉scale小于0.01的
        for (int i = filterList.Count - 1; i >= 0; i--)
        {
            if (filterList[i].transform.lossyScale.x <= 0.012f &&
                filterList[i].transform.lossyScale.y <= 0.012f &&
                filterList[i].transform.lossyScale.z <= 0.012f)
            {
                filterList.RemoveAt(i);
            }
        }
        //combine
        GameObject combineGo = null;

        if (filterList.Count > 0)
        {
            CombineInstance[] combines = new CombineInstance[filterList.Count];
            for (int i = 0; i < combines.Length; i++)
            {
                combines[i].mesh      = filterList[i].sharedMesh;
                combines[i].transform = filterList[i].transform.localToWorldMatrix;
            }
            combineGo = new GameObject("combine");
            combineGo.AddComponent <MeshRenderer>().sharedMaterial = sharedMat;
            MeshFilter combineFilter = combineGo.AddComponent <MeshFilter>();
            combineFilter.sharedMesh      = new Mesh();
            combineFilter.sharedMesh.name = copyGo.name + "_combine";
            combineFilter.sharedMesh.CombineMeshes(combines);
        }

        //移除已经被combine过的GameObject和Mesh(如果有子物体,则只移除MeshRenderer和MeshFilter)
        for (int i = 0; i < childrenList.Count; i++)
        {
            MeshRenderer childRenderer = childrenList[i].GetComponent <MeshRenderer>();
            MeshFilter   childFilter   = childrenList[i].GetComponent <MeshFilter>();
            if (null != childRenderer)
            {
                Object.DestroyImmediate(childRenderer);
            }
            if (null != childFilter)
            {
                Object.DestroyImmediate(childFilter);
            }
        }
        RemoveMeshRendererMeshFilter(copyGo.transform, copyGo.transform);
        if (null != combineGo)
        {
            combineGo.transform.SetParent(copyGo.transform);
        }

        //优化浮点数,主要是减少包体占用,内存不会变
        OptmizeAnimationFloat(copyClip, 3);
        AssetDatabase.CreateAsset(copyClip, g_storeDir + go.name + "_" + clip.name + ".anim");
        //删掉原来的Animation,用新的
        Animation ani = copyGo.GetComponent <Animation>();

        if (null != ani)
        {
            Object.DestroyImmediate(ani);
        }
        ani      = copyGo.AddComponent <Animation>();
        ani.clip = copyClip;
        //AnimationUtility.SetAnimationClips(ani, new AnimationClip[] { copyClip });

        MeshFilter[] filters = copyGo.GetComponentsInChildren <MeshFilter>();
        for (int i = 0; i < filters.Length; i++)
        {
            Mesh newMesh = Object.Instantiate(filters[i].sharedMesh);
            filters[i].sharedMesh = newMesh;
            if (i == 0)
            {
                AssetDatabase.CreateAsset(newMesh, g_storeDir + go.name + "_" + clip.name + "_" + "mesh.asset");
            }
            else
            {
                AssetDatabase.AddObjectToAsset(filters[i].sharedMesh, g_storeDir + go.name + "_" + clip.name + "_" + "mesh.asset");
            }
        }

        PrefabUtility.SaveAsPrefabAsset(copyGo, g_prefabDir + go.name + "_" + clip.name + ".prefab");
        AssetDatabase.SaveAssets();
        Object.DestroyImmediate(copyGo);
    }
    void Update()
    {
        if (prevWeaponL != testWeaponL)
        {
            prevWeaponL = testWeaponL;
            EquipSlots.SetItem(testWeaponL, HumanoidEquipSlots.SlotSpace.leftHand);
        }
        if (prevWeaponR != testWeaponR)
        {
            prevWeaponR = testWeaponR;
            EquipSlots.SetItem(testWeaponR, HumanoidEquipSlots.SlotSpace.rightHand);
        }

        if ((Character.IsUnderwater || Character.astral || Character.InAstral || Character.IsFlying) && EquipSlots.isHeld)
        {
            EquipSlots.isHeld = false;
        }

        if (Time.time - lastAttack > currentAttackComboTime)
        {
            attackCombo = 0;
        }
        attackCombo %= 3;
        animator.SetInteger("AttackCombo", attackCombo);

        bool leftHanded;
        bool hasShield;
        int  weaponType = GetWeaponType(EquipSlots.GetItem(HumanoidEquipSlots.SlotSpace.leftHand), EquipSlots.GetItem(HumanoidEquipSlots.SlotSpace.rightHand), out leftHanded, out hasShield);

        //Input stuff
        Vector2 input = new Vector2(Character.GetAxis("horizontal"), Character.GetAxis("vertical"));

        isStrafing = Character.GetToggle("r2Btn") && !Character.IsUnderwater && !Character.astral && !Character.InAstral && !Character.IsFlying;
        isBlocking = Character.GetToggle("l2Btn") && !Character.IsUnderwater && !Character.astral && !Character.InAstral && !Character.IsFlying;
        if ((!IsRunningCustomAnim || currentCustomAnim.canBeInterrupted) && !Character.IsUnderwater && !Character.astral && !Character.InAstral && !Character.IsFlying)
        {
            CustomAnimationData nextAnimData = null;
            Vector2             direction    = Character.mainShells.transform.forward.xz().normalized;

            if (Character.GetToggle("circleBtn"))
            {
                if (!prevRoll)
                {
                    prevRoll     = true;
                    nextAnimData = rollData;
                    if (isStrafing && !input.IsZero())
                    {
                        direction = input.normalized;
                    }
                }
            }
            else
            {
                prevRoll = false;
            }

            if (Character.GetToggle("squareBtn"))
            {
                if (!prevAttack && (IsRunningCustomAnim && currentCustomAnim != attackData || !IsRunningCustomAnim) && !isBlocking && weaponType > WEAPON_NONE)
                {
                    prevAttack = true;
                    if (EquipSlots.isHeld)
                    {
                        nextAnimData = attackData;

                        attackCombo++;
                        lastAttack             = Time.time;
                        currentAttackComboTime = nextAnimData.executionTime + attackComboTime;
                    }
                    else
                    {
                        nextAnimData = unsheathData;
                    }
                }
            }
            else
            {
                prevAttack = false;
            }

            if (Character.GetToggle("r1Btn"))
            {
                if (!prevSheath && weaponType > WEAPON_NONE)
                {
                    prevSheath = true;
                    if (EquipSlots.isHeld)
                    {
                        nextAnimData = sheathData;
                    }
                    else
                    {
                        nextAnimData = unsheathData;
                    }
                }
            }
            else
            {
                prevSheath = false;
            }

            if (nextAnimData != null && (!IsRunningCustomAnim || (currentCustomAnim.canBeInterrupted && currentCustomAnim != nextAnimData)))
            {
                SetCustomAnim(nextAnimData, direction);
            }
        }

        animator.SetFloat("StrafeDir", PercentClockwise(Character.mainShells.transform.forward.xz().normalized, input.normalized));
        animator.SetInteger("WeaponType", weaponType);
        animator.SetBool("LeftHanded", leftHanded);
        animator.SetBool("HasShield", hasShield);

        //Custom anim stuff
        animator.SetLayerWeight(animator.GetLayerIndex("Upperbody"), ((IsRunningCustomAnim && currentCustomAnim.isUpperbody) || EquipSlots.isHeld) ? 1 : 0);
        animator.SetBool("BlockMain", IsRunningCustomAnim && currentCustomAnim.blockMainLayerAnim);
        animator.SetBool("BlockUpper", (IsRunningCustomAnim && currentCustomAnim.blockUpperLayerAnim) || isBlocking);
        animator.SetBool("Block", isBlocking);
        Character.blockMovement = (IsRunningCustomAnim && currentCustomAnim.blockMovement) || isStrafing;
        Character.blockRotation = (IsRunningCustomAnim && currentCustomAnim.blockRotation) || isStrafing;
        if (IsRunningCustomAnim)
        {
            if (!toggledCustomAnim)
            {
                animator.SetTrigger(currentCustomAnim.animationToggleName);
                toggledCustomAnim = true;
            }

            if (currentCustomAnim.distanceTravelled > float.Epsilon)
            {
                Vector2 nextPosition = customAnimStartPos + customAnimStartDir * currentCustomAnim.distanceTravelled * currentCustomAnim.travelMap.Evaluate(CustomAnimPercentPlayed);
                Character.SetPosition(nextPosition);
            }
        }
        else
        {
            toggledCustomAnim = false;
        }

        //Strafe stuff
        animator.SetBool("Strafe", isStrafing && !input.IsZero());
        if (isStrafing && (!IsRunningCustomAnim || (IsRunningCustomAnim && !currentCustomAnim.blockMovement)))
        {
            Vector2 nextPosition = Character.mainShells.transform.position.xz() + input.normalized * strafeSpeed * Time.deltaTime;
            Character.SetPosition(nextPosition);
        }
    }
 private void SetCustomAnim(CustomAnimationData customAnim)
 {
     SetCustomAnim(customAnim, Character.mainShells.transform.forward.xz().normalized);
 }