关于修复预制体上UnityEngine.UI引用丢失的一种思路

news2024/11/13 18:34:56

在开发项目过程中,如果出现了Unity版本变化,有可能会导致一些预制体上的UI组件丢失,特别是大量UI脚本,明明一看就知道这个是Text组件,但是一个大大的missing出现在预制体上,让人产生了莫名的恐慌。

一、根据.prefab文件信息,分析引用的UGUI脚本信息

我们如果此时打开.prefab文件查看,大概可以看到如下信息(ForceText设置可以使得.prefab的显示内容以文本展示而非二进制格式)。

 很多高手对.prefab文件内容并不陌生,但是为了接下来的展开还是解释一下内容,从每个大节点开始讲解(节选部分重要内容):

1.GameObject

--- !u!1 &165095463815504087
GameObject:
  m_ObjectHideFlags: 0
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  serializedVersion: 6
  m_Component:
  - component: {fileID: 4433197073301798445}
  - component: {fileID: 5990753843237649034}
  - component: {fileID: 5075137301801018474}
  m_Layer: 5
  m_Name: Streak
  m_TagString: Untagged
  m_Icon: {fileID: 0}
  m_NavMeshLayer: 0
  m_StaticEditorFlags: 0
  m_IsActive: 1

`--- !u!1 &165095463815504087`: 此行表示该配置块(往后一块内容都简称为配置块)在此文件中的私有fileID;

`GameObject`: 表示一个预制体中的GameObject节点,如果一个预制体由多个GameObject组成,这块仅表示其中一个;

`m_Component`: 表示该GameObject所引用的私有fileID

`m_Name`: 顾名思义,这个GameObject的名称,可以在Hierarchy面板中很轻松找到名字,同时也可以方便在后续其他配置块中找到自身所属的GameObject;

2.RectTransform、CanvasRenderer

内容略去,该部分一般不会丢失,因为他不隶属于UnityEngine.UI,同时名字可以直接看到

3.MonoBehaviour

--- !u!114 &5075137301801018474
MonoBehaviour:
  m_ObjectHideFlags: 0
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_GameObject: {fileID: 165095463815504087}
  m_Enabled: 1
  m_EditorHideFlags: 0
  m_Script: {fileID: 11500000, guid: d6072c12dfea5c74897ce48533ec3f2a, type: 3}
  m_Name: 
  m_EditorClassIdentifier: 
  m_Material: {fileID: 0}
  m_Color: {r: 1, g: 1, b: 1, a: 1}
  m_RaycastTarget: 1
  m_OnCullStateChanged:
    m_PersistentCalls:
      m_Calls: []
  m_Sprite: {fileID: 0}
  m_Type: 0
  m_PreserveAspect: 0
  m_FillCenter: 1
  m_FillMethod: 4
  m_FillAmount: 1
  m_FillClockwise: 1
  m_FillOrigin: 0
  m_UseSpriteMesh: 0

敲黑板,该块表示引用了一个MonoBehavior脚本,有可能是自定义的,也有可能是其他继承自Component的脚本,这是我们解析出一个脚本是自定义脚本还是UI脚本的关键;

m_GameObject: {fileID: 165095463815504087} ,表示该脚本所属的GameObject,根据fileID向文件内索引,对应上文中的`--- !u!1 &165095463815504087`,所以是Streak上挂载的一个脚本

m_Script: {fileID: 11500000, guid: d6072c12dfea5c74897ce48533ec3f2a, type: 3},表示该脚本的引用信息,fileID表示所属的文件ID,如果是自定义脚本,通常都是11500000(但有例外,我所使用的Unity2019中,UnityEngine.UI中的也是11500000),如果是dll集,则表示dll中某个具体类的引用,guid则表示他在Unity中所归属的具体文件,type略去,暂时不影响复原操作

 这两条配置项是所有配置块都会存在的内容,而我们需要根据接下来的配置项,来推测一个MonoBehavior大概率可能属于哪一类型的UGUI脚本

  m_Material: {fileID: 0}
  m_Color: {r: 1, g: 1, b: 1, a: 1}
  m_RaycastTarget: 1
  m_OnCullStateChanged:
    m_PersistentCalls:
      m_Calls: []
  m_Sprite: {fileID: 0}
  m_Type: 0
  m_PreserveAspect: 0
  m_FillCenter: 1
  m_FillMethod: 4
  m_FillAmount: 1
  m_FillClockwise: 1
  m_FillOrigin: 0
  m_UseSpriteMesh: 0

其实很容易就发现了一个关键字`m_Sprite`,这大概率就是Image组件所使用的配置项,同时`m_FillCenter`等选项基本可以认定了这就是Image组件,因此,我们只需要根据本工程的Image的fileID,guid,type3个信息,修改该块中`m_Script`项即可复原丢失的引用。

二、索引出本项目中所有的UGUI信息

将所有集成自Component且出自程序集UnityEngine.UI的类型,添加到GameObject上,制成预制体,并根据上述分析获得fileID,guid,type,并记录到文件中。

    private static void StatisticOrderedScriptGUIDs(string asmName, string fileName)
    {
        var g = new GameObject();
        var asm = Assembly.Load(asmName);
        var types = asm.GetTypes();
        var guids = new List<FileTypeGUID>();
        long localId;
        string guid;
        foreach (var type in types)
        {
            // 抽象类或不继承自Component的类过滤
            if (type.IsAbstract || !type.IsSubclassOf(typeof(Component)))
            {
                continue;
            }
            g.name = type.Name;
            var component = g.AddComponent(type);
            if (component)
            {
                // 此处设置一个临时路径
                var prefabPath = $"Assets/Editor/GUIDPrefab/{type.Name}.prefab";
                // 自定义方法,根据文件名判断文件夹是否存在,不存在则创建
                FileHelper.CreateDirectoryIfNotExistByFilename(prefabPath);
                var success = false;
                PrefabUtility.SaveAsPrefabAsset(g, prefabPath, out success);
                AssetDatabase.Refresh();
                var prefab = AssetDatabase.LoadAssetAtPath(prefabPath, type);
                if (!prefab)
                {
                    Debug.LogError($"type:{type} cannot load, path:{prefabPath}");
                    continue;
                }
                if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(prefab, out guid, out localId))
                {
                    var fileId = $"&{localId}";
                    var metaLines = File.ReadAllLines(Path.GetFullPath(prefabPath));
                    var foundLine = false;
                    foreach (var line in metaLines)
                    {
                        if (line.IndexOf(fileId) > 0)
                        {
                            foundLine = true;
                            continue;
                        }
                        if (!foundLine)
                        {
                            continue;
                        }
                        if (line.IndexOf("m_Script:") > 0)
                        {
                            AnalysisScriptLine(line, out long realFileId, out string realGuid, out int fileType);
                            guids.Add(new FileTypeGUID(type, realFileId, realGuid, fileType));
                        }
                    }
                }
                GameObject.DestroyImmediate(component);
            }
        }
        GameObject.DestroyImmediate(g);
        var json = JsonConvert.Serialize(guids, true);
        Debug.Log(json);
        // 将收集的信息存储下来,为后续分析具体.prefab时供参考
        var path = Application.dataPath.Replace("Assets", $"{fileName}.json");
        File.WriteAllText(path, json);
    }

    private static void AnalysisScriptLine(string line, out long fileId, out string guid, out int type)
    {
        fileId = 0;
        guid = string.Empty;
        type = 0;
        if (!line.Trim().StartsWith("m_Script:"))
        {
            return;
        }
        var index = line.IndexOf("{");
        var endIndex = line.LastIndexOf("}");
        var inside = line.Substring(index + 1, endIndex - index - 1);
        var arr = inside.Split(',');
        foreach (var item in arr)
        {
            var pair = item.Split(':');
            switch (pair[0].Trim())
            {
                case "fileID":
                    long.TryParse(pair[1].Trim(), out fileId);
                    break;
                case "guid":
                    guid = pair[1].Trim();
                    break;
                case "type":
                    int.TryParse(pair[1].Trim(), out type);
                    break;
            }
        }
    }

至于为什么参数asmName作为传入参数,当然是因为后续更新到了自定义开发脚本也可修复的原因。

通过上述步骤,我们调用 `StatisticOrderedScriptGUIDs("UnityEngine.UI", "uguiguids");` 获取了项目内所有UGUI组件的guids

三、动手尝试修复一个.prefab

这个先把一个预制体文件打开,随后随手修改其中MonoBehavior块中的fileID,guid后,该预制体在Unity中即呈现丢失引用状态。

然后我们需要编写一些代码来储存如下信息,CharacteristicInfo(UGUI类型的特征信息),FileTypeGUID(fileID, guid, type的相关信息),PrefabContent(整个.prefab文件读取后的可读内容),PrefabChunk(.prefab文件中的配置块),FileTypeGUIDCollection(FileTypeGUID的集合,不是简单用数组处理),

以下是代码信息,也可以跳过不看,自己尝试开发,因为思路已经都在上边了。

    private struct CharacteristicInfo
    {
        public string Characteristic { get; set; }
        public Type Type { get; set; }

        public CharacteristicInfo(string c, Type t)
        {
            Characteristic = c;
            Type = t;
        }
    }
    private class FileTypeGUID
    {
        // 该信息组对应的实际类型
        public Type Type { get; set; }
        public long FileId { get; set; }
        public string Guid { get; set; }
        public int FileType { get; set; }

        public FileTypeGUID(Type type, long fileId, string guid, int fileType)
        {
            Type = type;
            FileId = fileId;
            Guid = guid;
            FileType = fileType;
        }

        public override string ToString()
        {
            return $"Type:{Type.Name}, FileId:{FileId}, Guid:{Guid}, FileType:{FileType}";
        }
    }
    private class PrefabContent
    {
        public Object Object { get; private set; }
        private readonly List<PrefabChunk> _chunks = new List<PrefabChunk>();
        private readonly List<string> _head = new List<string>();
        private readonly Dictionary<long, string> _gameObjects = new Dictionary<long, string>();

        private PrefabContent(Object belonging)
        {
            Object = belonging;
        }

        public void Analysis(TryGetFileGUITypeDelegate tryGetHandler, IsConfusingTypeDelegate isConfusingTypeHandler)
        {
            var changeCount = 0;
            FileTypeGUID[] fileTypeGUIDs;
            foreach (var chunk in _chunks)
            {
                if (tryGetHandler.Invoke(chunk, out var item))
                {
                    if (isConfusingTypeHandler.Invoke(chunk, out fileTypeGUIDs))
                    {
                        Debug.LogError("=========== confusing warning ===========");
                        Debug.LogError($"chunk.Component is a confusing type, should confirm again, {chunk.PrefabContent.Object}", chunk.PrefabContent.Object);
                        foreach (var guid in fileTypeGUIDs)
                        {
                            Debug.LogError($"Type:{guid.Type}, FileID:{guid.FileId}, guid:{guid.Guid}, type:{guid.FileType}");
                        }
                        Debug.LogError("=========== end ===========");
                    }
                    if (chunk.ModifyM_Script(item.FileId, item.Guid, item.FileType))
                    {
                        changeCount++;
                    }
                }
            }
            Debug.Log($"修改了 {changeCount} 个组件");
        }

        public string[] GetLines()
        {
            var list = new List<string>();
            list.AddRange(_head);
            foreach (var chunk in _chunks)
            {
                list.AddRange(chunk.Lines);
            }
            return list.ToArray();
        }

        public string GetName(long id)
        {
            _gameObjects.TryGetValue(id, out var name);
            return name;
        }

        public static PrefabContent Parse(Object selected, string[] lines, CharacteristicInfo[] characteristics)
        {
            var count = lines.Length;
            var listInChunk = new List<string>();
            var content = new PrefabContent(selected);
            var id = 0L;
            var foundGameObjectTag = false;
            for (int i = 0; i < count; i++)
            {
                var line = lines[i];
                if (line.StartsWith("%"))
                {
                    content._head.Add(line);
                    continue;
                }
                if (line.StartsWith("---"))
                {
                    if (i + 1 < count && lines[i + 1].StartsWith("GameObject:"))
                    {
                        var andIndex = line.IndexOf('&');
                        var idString = line.Substring(andIndex + 1);
                        long.TryParse(idString, out id);
                        foundGameObjectTag = true;
                    }

                    if (listInChunk.Count != 0)
                    {
                        var chunk = new PrefabChunk(content, listInChunk.ToArray(), characteristics);

                        content._chunks.Add(chunk);
                        listInChunk.Clear();
                    }
                    listInChunk.Add(line);
                    continue;
                }
                if (foundGameObjectTag)
                {
                    var nameTag = "m_Name:";
                    var nameIndex = line.IndexOf(nameTag);
                    if (!string.IsNullOrEmpty(line) && nameIndex != -1)
                    {
                        var name = line.Substring(nameIndex + nameTag.Length).Trim();
                        content._gameObjects[id] = name;
                        foundGameObjectTag = false;
                    }
                }
                listInChunk.Add(line);
            }
            // 添加剩余的
            if (listInChunk.Count != 0)
            {
                var chunk = new PrefabChunk(content, listInChunk.ToArray(), characteristics);
                content._chunks.Add(chunk);
                listInChunk.Clear();
            }
            return content;
        }
    }
    private class PrefabChunk
    {
        private const string ScriptFormat = "  m_Script: {fileID: #FILEID#, guid: #GUID#, type: #TYPE#}";

        public string Name { get; private set; }
        public PrefabContent PrefabContent { get; private set; }
        public Type ComponentType { get; private set; }
        public string[] Lines { get; private set; }

        public long FileID { get { return _fileID; } }
        private long _fileID;

        public string GUID { get { return _guid; } }
        private string _guid;

        public int Type { get { return _type; } }
        private int _type;

        private int _index;

        public PrefabChunk(PrefabContent content, string[] lines, CharacteristicInfo[] characteristics)
        {
            PrefabContent = content;
            Lines = lines;
            FindName();
            FindType(characteristics);
            FindScriptLine();
        }

        private void FindName()
        {
            var line = FindLine("m_GameObject:", out var gameObjectIndex);
            if (string.IsNullOrEmpty(line) && gameObjectIndex == -1)
            {
                return;
            }
            var gameObjectContent = line.Substring(gameObjectIndex);
            if (string.IsNullOrEmpty(gameObjectContent))
            {
                return;
            }
            gameObjectContent = gameObjectContent.Trim().Trim('{').Trim('}');
            var filedIDTag = "fileID:";
            var fileIDIndex = gameObjectContent.IndexOf(filedIDTag);
            if (fileIDIndex == -1)
            {
                return;
            }
            var idString = gameObjectContent.Substring(fileIDIndex + filedIDTag.Length);
            long.TryParse(idString, out var id);
            if (id == 0)
            {
                return;
            }
            Name = PrefabContent.GetName(id);
        }

        private void FindType(CharacteristicInfo[] characteristics)
        {
            foreach (var pair in characteristics)
            {
                if (FindCharacteristic(pair.Characteristic))
                {
                    ComponentType = pair.Type;
                }
            }
        }

        private void FindScriptLine()
        {
            _index = -1;
            var count = Lines.Length;
            for (int i = 0; i < count; i++)
            {
                if (Lines[i].Contains("m_Script"))
                {
                    _index = i;
                    break;
                }
            }
            if (_index == -1)
            {
                return;
            }
            AnalysisScriptLine(Lines[_index], out _fileID, out _guid, out _type);
        }

        public string FindLine(string tag, out int index)
        {
            index = -1;
            foreach (var line in Lines)
            {
                index = line.IndexOf(tag);
                if (index != -1)
                {
                    index += tag.Length;
                    return line;
                }
            }
            return string.Empty;
        }

        private bool FindCharacteristic(string tags)
        {
            var tagArr = tags.Split('&');
            var tagCount = tagArr.Length;
            var count = Lines.Length;
            var matchCount = 0;
            for (int tagIndex = 0; tagIndex < tagCount; tagIndex++)
            {
                var tag = tagArr[tagIndex];
                for (int i = 0; i < count; i++)
                {
                    var line = Lines[i];
                    if (line.Contains(tag))
                    {
                        matchCount++;
                    }
                }
            }
            return matchCount == tagCount;
        }

        public bool ModifyM_Script(long fileId, string guid, int type)
        {
            if (_index == -1)
            {
                return false;
            }
            if (_fileID == fileId && _guid == guid && _type == type)
            {
                Debug.Log($"{Name} is using correct reference, needn't to fix");
                return false;
            }
            var line = ScriptFormat.Replace("#FILEID#", fileId.ToString()).Replace("#GUID#", guid).Replace("#TYPE#", type.ToString());
            Debug.Log($"{Name}:{ComponentType} ---> fileID:{fileId}, guid:{guid}, type:{type}");
            Lines[_index] = line;
            return true;
        }
    }
    private class FileTypeGUIDCollection
    {
        private bool _inited;

        protected readonly Dictionary<Type, FileTypeGUID> _commonGUIDs = new Dictionary<Type, FileTypeGUID>();
        protected readonly Dictionary<Type, FileTypeGUID> _confusingGUIDs = new Dictionary<Type, FileTypeGUID>();

        public void Init(string path)
        {
            if (_inited)
            {
                return;
            }
            if (!File.Exists(path))
            {
                StatisticAllUGUIGUIDs();
            }
            var json = File.ReadAllText(path);
            var guids = JsonConvert.Deserialize<FileTypeGUID[]>(json);
            foreach (var item in guids)
            {
                _commonGUIDs[item.Type] = item;
                if (item.Type == typeof(VerticalLayoutGroup) || item.Type == typeof(HorizontalLayoutGroup))
                {
                    _confusingGUIDs[item.Type] = item;
                }
            }
            _inited = true;
        }

        public virtual bool TryGetValue(PrefabChunk chunk, out FileTypeGUID item)
        {
            if (chunk.ComponentType == null)
            {
                item = null;
                return false;
            }
            return _commonGUIDs.TryGetValue(chunk.ComponentType, out item);
        }

        public virtual bool IsConfusingType(PrefabChunk chunk, out FileTypeGUID[] fileTypeGUIDs)
        {
            fileTypeGUIDs = null;
            if (chunk.ComponentType == null)
            {
                return false;
            }
            if (_confusingGUIDs.ContainsKey(chunk.ComponentType))
            {
                fileTypeGUIDs = _confusingGUIDs.Values.ToArray();
                return true;
            }
            return false;
        }
    }

此外还需要2个委托和一个特征信息集合


    // 特征字典,根据配置块中特点返回组件类型
    private static readonly CharacteristicInfo[] UGUICharacteristics = new CharacteristicInfo[]
    {
        new CharacteristicInfo("m_Text&m_FontData", typeof(Text)),
        new CharacteristicInfo("m_InputType&m_OnEndEdit&m_OnValueChanged", typeof(InputField)),
        new CharacteristicInfo("m_Sprite&m_FillCenter", typeof(Image)),
        new CharacteristicInfo("m_OnCullStateChanged&m_Texture&m_UVRect", typeof(RawImage)),
        new CharacteristicInfo("m_OnClick&m_TargetGraphic&m_SpriteState&m_Interactable", typeof(Button)),
        new CharacteristicInfo("m_MovementType&m_Elasticity&m_Viewport&m_OnValueChanged", typeof(ScrollRect)),
        new CharacteristicInfo("m_AnimationTriggers&m_Interactable&m_TargetGraphic&m_HandleRectm_NumberOfSteps&m_OnValueChanged", typeof(Scrollbar)),
        new CharacteristicInfo("m_ShowMaskGraphic", typeof(Mask)),
        new CharacteristicInfo("m_Padding&m_ChildAlignment&m_CellSize&m_Spacing", typeof(GridLayoutGroup)),
        new CharacteristicInfo("m_Padding&m_ChildAlignment&m_Spacing&m_ChildForceExpandWidth&m_ChildForceExpandHeight&m_ChildControlWidth&m_ChildControlHeight&m_ChildScaleWidth&m_ChildScaleHeight", typeof(HorizontalLayoutGroup)),
        new CharacteristicInfo("m_Padding&m_ChildAlignment&m_Spacing&m_ChildForceExpandWidth&m_ChildForceExpandHeight&m_ChildControlWidth&m_ChildControlHeight", typeof(VerticalLayoutGroup)),
        new CharacteristicInfo("m_EffectColor&m_EffectDistance&m_UseGraphicAlpha", typeof(Outline)),
        new CharacteristicInfo("m_DynamicPixelsPerUnit&m_ReferenceResolution", typeof(CanvasScaler)),
        new CharacteristicInfo("m_IgnoreReversedGraphics&m_BlockingObjects&m_BlockingMask", typeof(GraphicRaycaster)),
        new CharacteristicInfo("m_FirstSelected&m_DragThreshold", typeof(EventSystem)),
        new CharacteristicInfo("m_HorizontalAxis&m_VerticalAxis&m_SubmitButton&m_CancelButton", typeof(StandaloneInputModule))
    };


    delegate bool TryGetFileGUITypeDelegate(PrefabChunk chunk, out FileTypeGUID fileTypeGUID);
    delegate bool IsConfusingTypeDelegate(PrefabChunk chunk, out FileTypeGUID[] confusingGUIDs);

随后,使用一段调用代码即可开始修复工作

    // 尝试修复引用丢失
    [MenuItem("Assets/Try To Fix UGUIComponent Missing")]
    private static void TryFixUGUIComponentMissing()
    {
        var collection = new FileTypeGUIDCollection();
        collection.Init(Application.dataPath.Replace("Assets", "uguiguids.json"));
        FixComponentMissingBase(collection.TryGetValue, collection.IsConfusingType, UGUICharacteristics);
    }

    private static void FixComponentMissingBase(TryGetFileGUITypeDelegate tryGetHandler, IsConfusingTypeDelegate isConfusingTypeHandler, CharacteristicInfo[] characteristics)
    {
        var selected = Selection.activeGameObject;
        // 对单个具体的prefab进行引用修复
        if (!selected)
        {
            return;
        }
        var prefabPath = AssetDatabase.GetAssetPath(selected);
        var lines = File.ReadAllLines(prefabPath);
        var prefabContent = PrefabContent.Parse(selected, lines, characteristics);
        prefabContent.Analysis(tryGetHandler, isConfusingTypeHandler);
        lines = prefabContent.GetLines();
        File.WriteAllLines(prefabPath, lines);
        AssetDatabase.Refresh();
        Debug.Log("Done");
    }

上述class为什么为private,是因为都限定在static class PrefabMissingTool中,并不希望外部访问,读者也可以根据自己的需要修改访问范围。

目前实现了对单个选中的prefab进行修复,也可以自行扩展为对复选或文件夹范围的prefab进行修复。

=========================== !!重要!! ==========================

因为`VerticalLayoutGroup`和`HorizontalLayoutGroup`两个类型中的特征信息(配置项)在作者的.prefab配置块中完全一致,因此无法区分,如果后续有发现更新的办法,会更新到文章中,或者也请读者指出更好的做法

=========================== 扩展 ==========================

因为可以搜集`UnityEngine.UI`的类型信息,那么同样,也可以收集`Assembly-CSharp`中继承自`Component`的信息,从原版本中收集信息后,到新版本根据匹配结果进行修改,那么也就可以修复在新版本中产生的自定义脚本挂载丢失的情况了。

后续发现有更好的办法时会及时更新。

github上可查看源码,已解耦合,仅依赖Newtonsoft,

DoyoFish/PrefabMissingFixTool: Quick to fix missing component on unity prefab (github.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/60132.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

头歌计算机组成原理MIPS寄存器文件设计

全部答案点击底部 <?xml version"1.0" encoding"UTF-8" standalone"no"?> <project source"2.15.0.2.exe" version"1.0"> This file is intended to be loaded by Logisim http://logisim.altervista.org &…

Linux | 二级页表的虚拟地址是怎么转换的?

文章目录页的概念可执行文件的虚拟地址二级页表的转换二级页表的优点页的概念 在聊文件系统时&#xff0c;我提到操作系统是以块为基本单位进行IO的&#xff0c;一个块的大小为4KB&#xff0c;在文件系统中它的名字叫做块&#xff0c;在内存系统中它的名字叫做页&#xff0c;p…

并发编程十 定时任务定时线程池

一 ScheduledThreadPoolExecutor 定时线程池类的类结构图 它接收SchduledFutureTask类型的任务&#xff0c;是线程池调度任务的最小单位&#xff0c;有三种提交任务的方式&#xff1a; schedulescheduledAtFixedRatescheduledWithFixedDelay 它采用DelayQueue存储等待的任务…

带你玩转序列模型之Bleu得分注意力模型语音识别

目录 一.Bleu得分 二.注意力模型直观理解 三.注意力模型 四.语音识别 五.触发字检测 一.Bleu得分 先跳过&#xff0c;等回头用得到了再来补。 二.注意力模型直观理解 在本周大部分时间中&#xff0c;你都在使用这个编码解码的构架&#xff08;a Encoder-Decoder archit…

MATLAB算法实战应用案例精讲-【图像处理】目标检测

前言 目标检测,也叫目标提取,是一种基于目标几何和统计特征的图像分割。它将目标的分割和识别合二为一,其准确性和实时性是整个系统的一项重要能力。尤其是在复杂场景中,需要对多个目标进行实时处理时,目标自动提取和识别就显得特别重要。 随着计算机技术的发展和计算机视…

AutoSAR基础:Port与Dio

AutoSAR基础:Port与Dio配置一.配置port1.Configurator1-1.进入Basic Editor->Port1-2.配置P00.0脚1-2-1.Port口1-2-2.Pin脚配置1-3.配置P00.11-3-1.Pin脚配置2.config导出生成代码3.代码部分3-1.config生成代码3-2.Write与Read3-2-1.Read函数3-2-2.Write函数二.配置Dio1.Con…

[附源码]计算机毕业设计基于SpringBoot的校园报修平台

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

qt使用http get和post

qt使用http get和post 本文目录qt使用http get和post准备get请求widge.hwidget.cpppost请求widge.hwidget.cpppost请求的数据格式参数写在url后面使用application/x-www-form-urlencoded使用application/json使用multipart/form-data传送文件准备 使用到网络编程&#xff0c;需…

Nginx配置实例-反向代理

1、实现效果 打开浏览器&#xff0c;在浏览器地址栏输入地址www.123.com&#xff0c;访问tomcat主页面。 2、准备工作 &#xff08;1&#xff09;在 liunx系统安装tomcat&#xff0c;使用默认端口8080 上传安装文件&#xff0c;并解压缩到/opt/tomcat。 进入tomcat的bin目录中…

[附源码]Python计算机毕业设计Django人员信息管理

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

ArrayList为什么线程不安全以及三种解决办法【详细】

目录不安全原因解决办法VectorCollectionsCopyOnWriteArrayList三种解决方式总结不安全原因 我们可以看一下ArrayList源码&#xff0c;找到add方法&#xff0c; public boolean add(E e) {ensureCapacityInternal(size 1); // Increments modCount!!elementData[size] e;r…

【java】Lambda表达式

文章目录体验Lambda表达式Lambda表达式的标准格式Lambda表达式的练习抽象方法无参无返回值抽象方法带参无返回值抽象方法带参带返回值Lambda表达式的省略模式Lambda表达式的注意事项Lambda表达式和匿名内部类的区别体验Lambda表达式 package heima.Lambda;import heima.多线程.…

HTML5期末大作业:旅游网页设计与实现——旅游风景区网站HTML+CSS+JavaScript 景点静态网页设计 学生DW静态网页设计

&#x1f468;‍&#x1f393;静态网站的编写主要是用 HTML DⅣV CSSJS等来完成页面的排版设计&#x1f469;‍&#x1f393;&#xff0c;一般的网页作业需要融入以下知识点&#xff1a;div布局、浮动定位、高级css、表格、表单及验证、js轮播图、音频视频Fash的应用、uli、下拉…

JMeter入门教程(9) --参数化

文章目录1.任务背景2.任务目标3.任务实操3.1 CSV数据文件1.任务背景 参数化是测试过程中很常用的一种技巧&#xff0c;可以将脚本中的某些输入用参数来代替&#xff0c;比如登陆时传递参数&#xff0c;在脚本运行时指定参数的取值范围和规则 2.任务目标 掌握基于JMeter性能测…

【浅学Java】SpringBoot创建和使用

SpringBoot创建和使用1. SpringBoot是什么2. SpringBoot的优点3. SpringBoot的创建3.1 使用idea创建3.2 测试项目_输出hello3.3 网页版创建SpringBoot4. 约定大于配置1. SpringBoot是什么 Spring的诞生是为了简化Java开发而创建的&#xff0c;而SpringBoot的诞生就是为了简化S…

一文带你理解【自然语言处理(NLP)】的基本概念及应用

觉得有帮助请点赞关注收藏~~~ 1.1 自然语言处理 1.1.1 自然语言处理主要研究对象 自然语言处理&#xff08;Natural Language Processing&#xff1a;NLP&#xff09;是以人类社会的语言信息&#xff08;比如语音和文本&#xff09;为主要研究对象&#xff0c;利用计算机技术来…

C++:深拷贝和浅拷贝——拷贝构造、赋值构造必须自定义

https://www.bilibili.com/video/BV1qT4y1X7cQ/?spm_id_from333.337.search-card.all.click&vd_sourced33b44674c517c8b7928e8d3ac316b37 1、赋值运算符重载 浅拷贝的错误代码&#xff1a; class Distance { public:int* dis NULL;Distance(int a){dis new int(a);}~…

轻量级xshell+manager远程监控jvisualvm

一、服务器端&#xff08;Linux&#xff0c;最小安装模式&#xff0c;没有图形界面&#xff09; 1.安装xauth 如果在Xshell中配置了X11转发后&#xff0c;出现如下提示&#xff1a; WARNING! The remote SSH server rejected X11 forwarding request. 则需要查看/etc/ssh/s…

esxi 6.7下安装openwrt(iStoreOS)网卡直通

esxi 6.7下安装openwrt&#xff08;iStoreOS&#xff09;网卡直通 esxi上创建一个iStoreOS系统的虚拟机&#xff0c;当主路由使用&#xff0c;网卡直通方式 1、工具 硬件&#xff1a; 工控机&#xff1a;装有esxi6.7系统&#xff08;192.168.100.2&#xff09;&#xff0c;配…

图像仿射变换与双线性插值

图像变换 下面的所有变换假设都是针对一幅图像&#xff0c;即一个三维数组&#xff08;HWC&#xff09;&#xff0c;这里为简单起见&#xff0c;假设图像都是单通道&#xff08;C1&#xff09;的。 (x,y)(x,y)(x,y): 原图像中某一点 A 的位置(x′,y′)(x′,y′)(x′,y′): 变换…