Unity资产文件浮点数修改为定点数工具记录


网络同步验证需要定点数,但是项目中大量资产文件使用了浮点数,需要工具来统一修改为定点数

  1. 通过将向浮点数添加特定的Attribute,并将类型替换成定点数类型,在OnPostprocessAllAssets时记录修改的cs文件GUID
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets,
        string[] movedFromAssetPaths) {
        _lastProcessedScriptTypes.Clear();
        _tsSerRecord = (TSSerScriptRecord)EditorGUIUtility.Load(TSSerRecordRelativePath);
        bool isDirty = false;
        foreach (string path in importedAssets) {
            Debug.Log("reimport Asset: " + path);
            if (Path.GetExtension(path) == ".cs") {
                string guid = AssetDatabase.AssetPathToGUID(path);
                var monoScript = AssetDatabase.LoadAssetAtPath<MonoScript>(path);
                if (monoScript != null) {
                    var type = monoScript.GetClass();
                    if (type != null) {
                        Debug.Log($"monoScript type: {type}");
                        if (type.IsSubclassOf(typeof(Object))) {
                            var tsFields =
                                (from field in type.GetFields(BindingFlags.Instance | BindingFlags.Static |
                                                              BindingFlags.Public | BindingFlags.NonPublic)
                                    where field.IsDefined(typeof(TSSerAttribute), false)
                                    select field).ToArray();
                            if (tsFields.Length <= 0) continue;
                            if (_tsSerRecord.changedScriptGuids.Contains(guid)) continue;
                            _tsSerRecord.changedScriptGuids.Add(guid);
                            isDirty = true;
                        }
                    }
                }
            }
        }

        if (isDirty) {
            EditorUtility.SetDirty(_tsSerRecord);
            AssetDatabase.Refresh();
        }
    }
  1. 通过FR2查找引用插件,查找到所有引用此脚本的资产文件
  2. 读取查找到的资产文件的yaml(通过YamlDotNet),遍历所有的Document,通过对比yaml的m_Script中的GUID确定yaml中信息位置
  3. 通过yaml可以得到修改前的旧值通过SerializedObject查找SerializedProperty设置转换后的定点值,最后应用修改ApplyModifiedProperties
static void ProcessTsAttributeSO(List<FieldInfo> fieldList, string scriptGuid, ScriptableObject so)
{
    var path = AssetDatabase.GetAssetPath(so);
    path = Path.Combine(Application.dataPath.Replace("/Assets", ""), path);
    var yaml = LoadYamlStream(path);
    if (yaml == null)
    {
        Debug.LogError($"LoadYamlStream Error {path}");
        return;
    }
    for (int i = 0; i < yaml.Documents.Count; i++)
    {
        var mapping = (YamlMappingNode)yaml.Documents[i].RootNode;
        foreach (var entry in mapping.Children)
        {
            if (entry.Key.ToString().Contains("MonoBehaviour"))
            {
                if (entry.Value is YamlMappingNode monoMapping)
                {
                    string guid =
                        ((monoMapping.Children["m_Script"] as YamlMappingNode)?.Children["guid"] as
                            YamlScalarNode)?.Value;
                    if (guid == scriptGuid)
                    {
                        var serObj = new SerializedObject(so);
                        bool isDirty = false;
                        foreach (var field in fieldList)
                        {
                            var uncovertNode = monoMapping.Children[field.Name];
                            isDirty = SingleValueConvertTsValue(serObj, field, uncovertNode);
                        }

                        if (isDirty)
                        {
                            serObj.ApplyModifiedProperties();
                            EditorUtility.SetDirty(so);
                        }
                    }
                }
            }
        }
    }
}
    static bool SingleValueConvertTsValue(SerializedObject serObj, FieldInfo fi, YamlNode uncovertNode)
    {
        var fieldType = fi.FieldType;

        #region FP
        if (fieldType == typeof(FP))
        {
            var targetNode = uncovertNode as YamlScalarNode;
            if (targetNode != null)
            {
                if (float.TryParse(targetNode.Value,
    out var oldValue))
                {
                    serObj.FindProperty(fi.Name)
                            .FindPropertyRelative("_serializedValue")
                            .longValue =
                        ((FP)oldValue).RawValue;
                    return true;
                }
            }
        }

        #endregion FP end

        #region TSVector2
        if (fieldType == typeof(TSVector2))
        {
            var targetNode = uncovertNode as YamlMappingNode;
            if(targetNode != null)
            {
                bool boolX, boolY;
                var strX = (targetNode.Children["x"] as YamlScalarNode)?.Value;
                var strY = (targetNode.Children["y"] as YamlScalarNode)?.Value;
                if(boolX = float.TryParse(strX, out var oldFloatX))
                {
                    serObj.FindProperty(fi.Name)
                        .FindPropertyRelative("x")
                        .FindPropertyRelative("_serializedValue").longValue = ((FP)oldFloatX).RawValue;
                }

                if (boolY = float.TryParse(strY, out var oldFloatY))
                {
                    serObj.FindProperty(fi.Name)
                        .FindPropertyRelative("y")
                        .FindPropertyRelative("_serializedValue").longValue = ((FP)oldFloatY).RawValue;
                }
                return boolX && boolY;
            }
        }
        #endregion TSVector2 end

        #region TSVector
        if (fieldType == typeof(TSVector))
        {
            var targetNode = uncovertNode as YamlMappingNode;
            if (targetNode != null)
            {
                bool boolX, boolY, boolZ;
                var strX = (targetNode.Children["x"] as YamlScalarNode)?.Value;
                var strY = (targetNode.Children["y"] as YamlScalarNode)?.Value;
                var strZ = (targetNode.Children["z"] as YamlScalarNode)?.Value;
                if (boolX = float.TryParse(strX, out var oldFloatX))
                {
                    serObj.FindProperty(fi.Name)
                        .FindPropertyRelative("x")
                        .FindPropertyRelative("_serializedValue").longValue = ((FP)oldFloatX).RawValue;
                }

                if (boolY = float.TryParse(strY, out var oldFloatY))
                {
                    serObj.FindProperty(fi.Name)
                        .FindPropertyRelative("y")
                        .FindPropertyRelative("_serializedValue").longValue = ((FP)oldFloatY).RawValue;
                }

                if (boolZ = float.TryParse(strZ, out var oldFloatZ))
                {
                    serObj.FindProperty(fi.Name)
                        .FindPropertyRelative("z")
                        .FindPropertyRelative("_serializedValue").longValue = ((FP)oldFloatZ).RawValue;
                }
                return boolX && boolY && boolZ;
            }
        }

        #endregion TSVector2 end

        #region Curve

        if (fieldType == typeof(Curve))
        {
            var targetNode = uncovertNode as YamlMappingNode;
            if (targetNode != null)
            {
                // 空曲线可能会出现空情况
                if (targetNode.Children.ContainsKey("m_Curve"))
                {
                    var curveSeqNode = targetNode.Children["m_Curve"] as YamlSequenceNode;
                    if (curveSeqNode != null)
                    {
                        var curvekeyListSerProperty = serObj.FindProperty(fi.Name)
                            .FindPropertyRelative("keys")
                            .FindPropertyRelative("innerlist");
                        curvekeyListSerProperty.ClearArray();
                        bool errorState = true;
                        for (int i = 0; i < curveSeqNode.Children.Count; i++)
                        {
                            var mapNode = curveSeqNode.Children[i] as YamlMappingNode;
                            if (mapNode != null)
                            {
                                bool boolTime, boolValue, boolInTangent, boolOutTangent;

                                var strTime = (mapNode.Children["time"] as YamlScalarNode)?.Value;
                                var strValue = (mapNode.Children["value"] as YamlScalarNode)?.Value;
                                var strInTangent = (mapNode.Children["inSlope"] as YamlScalarNode)?.Value;
                                var strOutTangent = (mapNode.Children["outSlope"] as YamlScalarNode)?.Value;
								
								这个是通过SerializedProperty修改List类型
                                curvekeyListSerProperty.InsertArrayElementAtIndex(i);
                                var insertElement = curvekeyListSerProperty.GetArrayElementAtIndex(i);

                                if (boolTime = float.TryParse(strTime, out var floatTime))
                                {
                                    insertElement
                                        .FindPropertyRelative("position")
                                        .FindPropertyRelative("_serializedValue")
                                        .longValue = ((FP)floatTime).RawValue;
                                }
                                if (boolValue = float.TryParse(strValue, out var floatValue))
                                {
                                    insertElement
                                        .FindPropertyRelative("value")
                                        .FindPropertyRelative("_serializedValue")
                                        .longValue = ((FP)floatValue).RawValue;
                                }
                                if (boolInTangent = float.TryParse(strInTangent, out var floatInTangent))
                                {
                                    insertElement
                                        .FindPropertyRelative("tangentIn")
                                        .FindPropertyRelative("_serializedValue")
                                        .longValue = ((FP)floatInTangent).RawValue;
                                }
                                if (boolOutTangent = float.TryParse(strOutTangent, out var floatOutTangent))
                                {
                                    insertElement
                                        .FindPropertyRelative("tangentOut")
                                        .FindPropertyRelative("_serializedValue")
                                        .longValue = ((FP)floatOutTangent).RawValue;
                                }

                                errorState = errorState && boolTime && boolValue && boolInTangent && boolOutTangent;
                            }
                        }
                        return errorState;
                    }
                }
            }
        }


注意 当在MonoBehaviour类型cs脚本中修改值时,资产文件yaml其实是不变的,但是如果你这时候修改Inspector,yaml将会被刷新成新信息,你就无法获得以前的旧值了,上面的核心思路就是找到引用资产文件,通过yaml获得旧值,通过SerializedObject设置新值和刷新yaml


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity的物理引擎使用的是计算机中的定点数(Fixed Point)来进行计算。定点数是一种用固定小数部分的数来表示实数的数值表示方法。 在计算机中,浮点数定点数是两种常见的表达实数的方式。浮点数使用科学计数法来表示实数,它包含小数部分和指数部分。由于浮点数的存储和计算都需要考虑指数部分,所以相对于定点数来说,浮点数的运算速度更慢。 而定点数则采用一种固定的小数位来表示实数,没有指数部分。在Unity的物理引擎中,使用定点数可以提高运算速度和准确性,因为它不需要进行复杂的浮点数运算,只需要进行简单的整数运算即可。 Unity的物理引擎使用的是定点数的一种特殊形式,称为"Fixed"。在Unity中,Fixed数据类型类似于整数,但实际上它以定点数的形式进行存储和计算。Fixed数据类型将一个整数分为整数部分和小数部分,小数部分的位数是固定的,通常为16位。通过使用Fixed数据类型,Unity可以在进行物理计算时更加准确地模拟物理行为,同时也能提高运算速度,使游戏运行更加流畅。 总之,Unity的物理引擎使用的是定点数来进行计算。它通过定义一个固定的小数部分来表示实数,并且通过使用Fixed数据类型来存储和计算这些实数。这种使用定点数的方式可以提高运算速度和准确性,在物理模拟和游戏开发中起到非常重要的作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值