Unity 自定义批量打包工具

打包配置项

using UnityEngine;
using System.Collections.Generic;namespace MYTOOL.Build
{[System.Flags]public enum VersionOptions{None = 0,Major = 1,Minor = 4,Build = 8,Revision = 0x10,}/// <summary>/// 批量打包配置文件/// </summary>[CreateAssetMenu]public class BatchBuildProfile : ScriptableObject{public VersionOptions versionOptions = VersionOptions.Revision;public List<BuildTask> tasks = new List<BuildTask>(0);}
}

打包功能

using UnityEditor;
using UnityEngine;
using System;
using System.IO;
using System.Collections.Generic;namespace MYTOOL.Build
{public class LogMessage{public LogType type;public string message;public LogMessage(LogType type, string message){this.type = type;this.message = message;}}[CustomEditor(typeof(BatchBuildProfile))]public class BatchBuildProfileInspector : Editor{//配置文件private BatchBuildProfile profile;//折叠栏private Dictionary<BuildTask, bool> foldoutMap;//记录日志private List<LogMessage> logsList;private void OnEnable(){profile = target as BatchBuildProfile;foldoutMap = new Dictionary<BuildTask, bool>();logsList = new List<LogMessage>();}public override void OnInspectorGUI(){OnMenuGUI();OnListGUI();serializedObject.ApplyModifiedProperties();if (GUI.changed)EditorUtility.SetDirty(profile);}/// <summary>/// 菜单项/// </summary>private void OnMenuGUI(){EditorGUILayout.HelpBox($"已有打包工作项:{profile.tasks.Count}个", MessageType.Info);EditorGUILayout.HelpBox($"打包时会先进行排序, 优先打包当前平台【{EditorUserBuildSettings.activeBuildTarget}】", MessageType.Info);//限制20个if (profile.tasks.Count < 20){//新建工作项if (GUILayout.Button("新建工作项", GUILayout.Height(30))){Undo.RecordObject(profile, "Create");string buildPath = Path.Combine(Directory.GetParent(Application.dataPath).FullName, ".Build");if (Directory.Exists(buildPath) == false){Directory.CreateDirectory(buildPath);Debug.LogFormat("创建构建目录:{0}", buildPath);}var task = new BuildTask(PlayerSettings.productName, (MyBuildTarget)EditorUserBuildSettings.activeBuildTarget, buildPath);profile.tasks.Add(task);}}else{EditorGUILayout.HelpBox($"无法新建打包工作项", MessageType.Warning);}if (profile.tasks.Count > 0){//清空GUI.color = Color.yellow;if (GUILayout.Button("清空工作项", GUILayout.Height(30))){Undo.RecordObject(profile, "Clear");if (EditorUtility.DisplayDialog("提醒", "是否确认清理所有打包工作项?", "确定", "取消")){Debug.LogWarningFormat("清理{0}个打包工作项", profile.tasks.Count);profile.tasks.Clear();foldoutMap.Clear();}}//开始打包GUI.color = Color.cyan;if (GUILayout.Button("开始打包", GUILayout.Height(30))){if (EditorUtility.DisplayDialog("确认操作", "即将开始打包过程,这可能需要一些时间。您希望继续吗?", "继续", "取消")){logsList.Clear();OnBuild(false);}return;}//清理并打包GUI.color = Color.yellow;if (GUILayout.Button("清理并打包", GUILayout.Height(30))){if (EditorUtility.DisplayDialog("确认操作", "即将进行清理并开始打包过程,这可能需要一些时间。您希望继续吗?", "继续", "取消")){if (EditorUtility.DisplayDialog("重要提醒", "清理操作将移除当前构建平台的所有文件,请确保已备份重要数据。是否要继续?此操作不可逆。", "确定继续", "取消")){logsList.Clear();OnBuild(true);}}return;}}GUI.color = Color.white;//排序if (profile.tasks.Count > 1){if (GUILayout.Button("排序工作项", GUILayout.Height(30))){Debug.Log("排序打包工作项");profile.tasks.Sort(new BuildTaskComparer());return;}}}/// <summary>/// 任务项/// </summary>private void OnListGUI(){//新旧版本号if (profile.tasks.Count > 0){GUILayout.Space(10);//版本选项GUILayout.BeginHorizontal();GUILayout.Label("版本选项:", GUILayout.Width(70));var newVO = (VersionOptions)EditorGUILayout.EnumFlagsField(profile.versionOptions);if (profile.versionOptions != newVO){Undo.RecordObject(profile, "Version Options");profile.versionOptions = newVO;}GUILayout.EndHorizontal();GUILayout.BeginHorizontal();GUILayout.Label("旧版本号:", GUILayout.Width(70));GUILayout.Label(PlayerSettings.bundleVersion);GUILayout.EndHorizontal();GUILayout.BeginHorizontal();GUILayout.Label("新版本号:", GUILayout.Width(70));GUILayout.Label(GetNewVersion(profile.versionOptions));GUILayout.EndHorizontal();}for (int i = 0; i < profile.tasks.Count; i++){var task = profile.tasks[i];if (foldoutMap.ContainsKey(task) == false){foldoutMap.Add(task, true);}GUI.contentColor = task.enableTask ? Color.green : Color.white;GUILayout.Space(10);GUILayout.BeginHorizontal("Badge");GUILayout.Space(20);foldoutMap[task] = EditorGUILayout.Foldout(foldoutMap[task], task.ToString(), true);if (GUILayout.Button(EditorGUIUtility.IconContent("TreeEditor.Trash"), "IconButton", GUILayout.Width(20))){Undo.RecordObject(profile, "Delete Task");foldoutMap.Remove(task);profile.tasks.Remove(task);break;}GUILayout.EndHorizontal();//折叠栏if (foldoutMap[task]){GUI.contentColor = Color.white;GUILayout.BeginVertical("Box");//是否激活GUILayout.BeginHorizontal();GUILayout.Label("是否激活:", GUILayout.Width(70));task.enableTask = GUILayout.Toggle(task.enableTask, "");GUILayout.EndHorizontal();//打包场景GUILayout.BeginHorizontal();GUILayout.Label("打包场景:", GUILayout.Width(70));if (GUILayout.Button("+", GUILayout.Width(20f))){task.sceneAssets.Add(null);}GUILayout.EndHorizontal();//场景列表if (task.sceneAssets.Count > 0){OnSceneAssetsList(task);}//产品名称GUILayout.BeginHorizontal();GUILayout.Label("产品名称:", GUILayout.Width(70));var newPN = GUILayout.TextField(task.productName);if (task.productName != newPN){Undo.RecordObject(profile, "Product Name");task.productName = newPN;}GUILayout.EndHorizontal();//打包平台GUILayout.BeginHorizontal();GUILayout.Label("打包平台:", GUILayout.Width(70));var newBT = (MyBuildTarget)EditorGUILayout.EnumPopup(task.buildTarget);if (task.buildTarget != newBT){Undo.RecordObject(profile, "Build Target");task.buildTarget = newBT;//这些平台只能使用IL2CPPif (task.buildTarget == MyBuildTarget.iOS || task.buildTarget == MyBuildTarget.WebGL || task.buildTarget == MyBuildTarget.WeixinMiniGame){task.scriptMode = ScriptingImplementation.IL2CPP;}//其它平台默认切换到Playerif (task.buildTarget != MyBuildTarget.StandaloneWindows64 && task.buildTarget != MyBuildTarget.StandaloneLinux64 && task.buildTarget != MyBuildTarget.NoTarget){task.buildSubtarget = StandaloneBuildSubtarget.Player;}}GUILayout.EndHorizontal();//Windows Linux添加打包子平台if (task.buildTarget == MyBuildTarget.StandaloneWindows64 || task.buildTarget == MyBuildTarget.StandaloneLinux64){GUILayout.BeginHorizontal();GUILayout.Label("打包子平台:", GUILayout.Width(70));var newBS = (StandaloneBuildSubtarget)EditorGUILayout.EnumPopup(task.buildSubtarget);if (task.buildSubtarget != newBS){Undo.RecordObject(profile, "Build Subtarget");task.buildSubtarget = newBS;}GUILayout.EndHorizontal();}//打包选项GUILayout.BeginHorizontal();GUILayout.Label("打包选项:", GUILayout.Width(70));var newBO = (BuildOptions)EditorGUILayout.EnumFlagsField(task.buildOptions);if (task.buildOptions != newBO){Undo.RecordObject(profile, "Build Options");task.buildOptions = newBO;}GUILayout.EndHorizontal();//脚本模式GUILayout.BeginHorizontal();GUILayout.Label("脚本模式:", GUILayout.Width(70));var newSM = (ScriptingImplementation)EditorGUILayout.EnumPopup(task.scriptMode);if (task.scriptMode != newSM){Undo.RecordObject(profile, "Script Mode");task.scriptMode = newSM;}GUILayout.EndHorizontal();//打包路径GUILayout.BeginHorizontal();GUILayout.Label("打包路径:", GUILayout.Width(70));GUILayout.TextField(task.buildPath);if (GUILayout.Button("浏览", GUILayout.Width(40f))){string path = EditorUtility.SaveFolderPanel("Build Path", task.buildPath, "");if (!string.IsNullOrWhiteSpace(path)){task.buildPath = path;}GUIUtility.ExitGUI();}GUILayout.EndHorizontal();//安卓平台添加其它选项if (task.buildTarget == MyBuildTarget.Android){GUILayout.BeginHorizontal();GUILayout.Label("keystore:", GUILayout.Width(70));PlayerSettings.Android.keystorePass = EditorGUILayout.PasswordField(PlayerSettings.Android.keystorePass);GUILayout.EndHorizontal();GUILayout.BeginHorizontal();GUILayout.Label("keyalias:", GUILayout.Width(70));PlayerSettings.Android.keyaliasPass = EditorGUILayout.PasswordField(PlayerSettings.Android.keyaliasPass);GUILayout.EndHorizontal();//导出工程GUILayout.BeginHorizontal();GUILayout.Label("导出工程:", GUILayout.Width(70));EditorUserBuildSettings.exportAsGoogleAndroidProject = GUILayout.Toggle(EditorUserBuildSettings.exportAsGoogleAndroidProject, "");GUILayout.EndHorizontal();}GUILayout.EndVertical();}}}private void OnSceneAssetsList(BuildTask task){GUILayout.BeginHorizontal();GUILayout.Space(75);GUILayout.BeginVertical("Badge");for (int j = 0; j < task.sceneAssets.Count; j++){var sceneAsset = task.sceneAssets[j];GUILayout.BeginHorizontal();GUILayout.Label($"{j + 1}.", GUILayout.Width(20));task.sceneAssets[j] = EditorGUILayout.ObjectField(sceneAsset, typeof(SceneAsset), false) as SceneAsset;if (GUILayout.Button("↑", "MiniButtonLeft", GUILayout.Width(20))){if (j > 0){Undo.RecordObject(profile, "Move Up Scene Assets");var temp = task.sceneAssets[j - 1];task.sceneAssets[j - 1] = sceneAsset;task.sceneAssets[j] = temp;}}if (GUILayout.Button("↓", "MiniButtonMid", GUILayout.Width(20))){if (j < task.sceneAssets.Count - 1){Undo.RecordObject(profile, "Move Down Scene Assets");var temp = task.sceneAssets[j + 1];task.sceneAssets[j + 1] = sceneAsset;task.sceneAssets[j] = temp;}}if (GUILayout.Button("+", "MiniButtonMid", GUILayout.Width(20))){Undo.RecordObject(profile, "Add Scene Assets");task.sceneAssets.Insert(j + 1, null);break;}if (GUILayout.Button("-", "MiniButtonMid", GUILayout.Width(20))){Undo.RecordObject(profile, "Delete Scene Assets");task.sceneAssets.RemoveAt(j);break;}GUILayout.EndHorizontal();}GUILayout.EndVertical();GUILayout.EndHorizontal();}/// <summary>/// 开始打包/// </summary>/// <param name="clearBuild">清理旧的构建</param>private void OnBuild(bool clearBuild){//排序,优先当前平台的任务profile.tasks.Sort(new BuildTaskComparer());//旧版本号string oldVersion = PlayerSettings.bundleVersion;//新版本号string newVersion = GetNewVersion(profile.versionOptions);//设置新版本号PlayerSettings.bundleVersion = newVersion;try{for (int i = 0; i < profile.tasks.Count; i++){var task = profile.tasks[i];if (task.enableTask == false || task.buildTarget == MyBuildTarget.NoTarget){logsList.Add(new LogMessage(LogType.Log, $"跳过: {task}"));continue;}BuildTarget buildTarget = (BuildTarget)task.buildTarget;BuildTargetGroup targetGroup = BuildPipeline.GetBuildTargetGroup(buildTarget);BuildPlayerOptions buildPlayerOptions = SetBuildParams(targetGroup, task);EditorUtility.DisplayProgressBar("正在打包", profile.tasks[i].ToString(), (float)i + 1 / profile.tasks.Count);if (string.IsNullOrEmpty(buildPlayerOptions.locationPathName)){throw new Exception(($"无法打包 {task},产品名称可能为空"));}if (buildPlayerOptions.scenes.Length == 0){throw new Exception($"无法打包 {task},打包场景为空");}//切换平台if (buildTarget != EditorUserBuildSettings.activeBuildTarget){EditorUserBuildSettings.SwitchActiveBuildTarget(targetGroup, buildTarget);}PlayerSettings.SetScriptingBackend(targetGroup, task.scriptMode);string path = Path.GetDirectoryName(buildPlayerOptions.locationPathName);if (clearBuild && Directory.Exists(path)){Directory.Delete(path, true);}if (Directory.Exists(path) == false){Directory.CreateDirectory(path);}//开始打包var report = BuildPipeline.BuildPlayer(buildPlayerOptions);switch (report.summary.result){case UnityEditor.Build.Reporting.BuildResult.Unknown:logsList.Add(new LogMessage(LogType.Error, $"{task} 出现未知错误"));break;case UnityEditor.Build.Reporting.BuildResult.Succeeded:logsList.Add(new LogMessage(LogType.Log, $"{task} 打包耗时: {(report.summary.buildEndedAt - report.summary.buildStartedAt).TotalSeconds}秒"));break;case UnityEditor.Build.Reporting.BuildResult.Failed:string errorMsg = "\n";foreach (var file in report.GetFiles()){errorMsg += file.path + "\n";}foreach (var step in report.steps){foreach (var stepmsg in step.messages){errorMsg += "\n" + stepmsg.content;}errorMsg += "\n";}logsList.Add(new LogMessage(LogType.Error, $"{task} 打包失败: {errorMsg}"));break;case UnityEditor.Build.Reporting.BuildResult.Cancelled:logsList.Add(new LogMessage(LogType.Log, $"{task} 取消打包"));return;}//打包成功,打开目录并记录版本号if (report.summary.result == UnityEditor.Build.Reporting.BuildResult.Succeeded){File.WriteAllText(string.Format("{0}/__version.txt", path), newVersion);Application.OpenURL(path);}}}catch (Exception ex){//异常情况下还原版本号PlayerSettings.bundleVersion = oldVersion;Debug.LogFormat("还原打包版本号:{0}", oldVersion);Debug.LogException(ex);}finally{EditorUtility.ClearProgressBar();Debug.LogFormat("当前打包版本号:{0}", newVersion);foreach (var log in logsList){Debug.unityLogger.Log(log.type, log.message);}logsList.Clear();}}/// <summary>/// 获取新版本号/// </summary>/// <returns></returns>private string GetNewVersion(VersionOptions options){try{Version version = new Version(PlayerSettings.bundleVersion);int major = version.Major;              //主版本int minor = version.Minor;              //次版本int build = version.Build;              //构建版本int revision = version.Revision;        //修订版本//默认不处理if (options == VersionOptions.None){//revision += 1;}else{major += options.HasFlag(VersionOptions.Major) ? 1 : 0;minor += options.HasFlag(VersionOptions.Minor) ? 1 : 0;build += options.HasFlag(VersionOptions.Build) ? 1 : 0;revision += options.HasFlag(VersionOptions.Revision) ? 1 : 0;}if (revision >= 100){build += 1;revision = 0;}if (build >= 100){minor += 1;build = 0;}if (minor >= 100){major += 1;minor = 0;}return $"{major}.{minor}.{build}.{revision}";}catch (Exception){return "1.0.0.0";}}/// <summary>/// 设置构建参数/// </summary>/// <param name="targetGroup"></param>/// <param name="task"></param>/// <returns></returns>private BuildPlayerOptions SetBuildParams(BuildTargetGroup targetGroup, BuildTask task){BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions();List<string> levels = new List<string>();string[] activeLevels = EditorBuildSettingsScene.GetActiveSceneList(EditorBuildSettings.scenes);if (activeLevels.Length > 0){levels.AddRange(activeLevels);}for (int i = 0; i < task.sceneAssets.Count; i++){var scenePath = AssetDatabase.GetAssetPath(task.sceneAssets[i]);if (!string.IsNullOrEmpty(scenePath) && !levels.Contains(scenePath)){levels.Add(scenePath);}}buildPlayerOptions.scenes = levels.ToArray();buildPlayerOptions.target = (BuildTarget)task.buildTarget;buildPlayerOptions.subtarget = (int)task.buildSubtarget;buildPlayerOptions.targetGroup = targetGroup;buildPlayerOptions.options = task.buildOptions;buildPlayerOptions.locationPathName = GetBuildTargetPath(task.buildTarget, task.buildSubtarget, task.buildOptions, task.buildPath, task.productName);return buildPlayerOptions;}/// <summary>/// 获取构建路径/// </summary>/// <param name="buildTarget"></param>/// <param name="buildOptions"></param>/// <param name="buildPath"></param>/// <param name="productName"></param>/// <returns></returns>private string GetBuildTargetPath(MyBuildTarget buildTarget, StandaloneBuildSubtarget buildSubtarget, BuildOptions buildOptions, string buildPath, string productName){if (string.IsNullOrEmpty(productName)){return string.Empty;}bool isDevelopment = buildOptions.HasFlag(BuildOptions.Development);string currentDate = DateTime.Now.ToString("yyMMdd");string locationPathName = Path.Combine(buildPath, buildTarget.ToString(), buildSubtarget.ToString(), currentDate, productName);switch (buildTarget){case MyBuildTarget.StandaloneOSX:{if (isDevelopment)locationPathName += "_dev.app";elselocationPathName += ".app";}break;case MyBuildTarget.StandaloneWindows64:{if (isDevelopment)locationPathName += "_dev.exe";elselocationPathName += ".exe";}break;case MyBuildTarget.StandaloneLinux64:{if (isDevelopment)locationPathName += "_dev.x86_64";elselocationPathName += ".x86_64";}break;case MyBuildTarget.Android:{if (isDevelopment)locationPathName += $"_{currentDate}_dev";elselocationPathName += $"_{currentDate}";if (EditorUserBuildSettings.exportAsGoogleAndroidProject == false)locationPathName += ".APK";}break;case MyBuildTarget.iOS:{if (isDevelopment)locationPathName += $"_{currentDate}_dev";elselocationPathName += $"_{currentDate}";}break;}return locationPathName;}}
}

任务配置项

using System;
using System.Collections.Generic;
using UnityEditor;namespace MYTOOL.Build
{/// <summary>/// 打包的目标平台/// </summary>public enum MyBuildTarget{NoTarget = -2,//// 摘要://     Build a macOS standalone (Intel 64-bit).StandaloneOSX = 2,//// 摘要://     Build a Windows standalone.StandaloneWindows = 5,//// 摘要://     Build a Windows 64-bit standalone.StandaloneWindows64 = 19,//// 摘要://     Build a Linux 64-bit standalone.StandaloneLinux64 = 24,//// 摘要://     Build an iOS player.iOS = 9,//// 摘要://     Build an Android .apk standalone app.Android = 13,//// 摘要://     Build to WebGL platform.WebGL = 20,//// 摘要://     Build to WeixinMiniGame platform.WeixinMiniGame = 47,//// 摘要://     Build an OpenHarmony .hap standalone app.OpenHarmony = 48,}/// <summary>/// 打包工作项/// </summary>[Serializable]public class BuildTask{/// <summary>/// 是否激活/// </summary>public bool enableTask;/// <summary>/// 打包的产品名称/// </summary>public string productName;/// <summary>/// 打包的目标平台/// </summary>public MyBuildTarget buildTarget;/// <summary>/// 打包的目标子平台/// </summary>public StandaloneBuildSubtarget buildSubtarget;/// <summary>/// 打包的选项/// </summary>public BuildOptions buildOptions;/// <summary>/// 脚本模式/// </summary>public ScriptingImplementation scriptMode;/// <summary>/// 打包的保存路径/// </summary>public string buildPath;/// <summary>/// 打包的场景列表/// </summary>public List<SceneAsset> sceneAssets;/// <summary>/// 构造函数/// </summary>/// <param name="productName">产品名称</param>/// <param name="buildTarget">目标平台</param>/// <param name="buildPath">保存路径</param>public BuildTask(string productName, MyBuildTarget buildTarget, string buildPath){this.productName = productName;this.buildTarget = buildTarget;this.buildPath = buildPath;enableTask = true;buildSubtarget = StandaloneBuildSubtarget.Player;buildOptions = BuildOptions.CleanBuildCache;scriptMode = ScriptingImplementation.IL2CPP;sceneAssets = new List<SceneAsset>();}public override string ToString(){return string.Format("{0}【{1}-{2}】", productName, buildTarget, buildSubtarget);}}/// <summary>
/// BuildTask比较
/// </summary>
public class BuildTaskComparer : IComparer<BuildTask>
{public int Compare(BuildTask x, BuildTask y){if (x.enableTask && (BuildTarget)x.buildTarget == EditorUserBuildSettings.activeBuildTarget && (BuildTarget)y.buildTarget != EditorUserBuildSettings.activeBuildTarget){return -1; // x排在前}else if (y.enableTask && (BuildTarget)x.buildTarget != EditorUserBuildSettings.activeBuildTarget && (BuildTarget)y.buildTarget == EditorUserBuildSettings.activeBuildTarget){return 1; // y排在前}else if (x.enableTask && y.enableTask && x.buildTarget == y.buildTarget){return 0; //保持当前}else if (x.enableTask && x.buildTarget == y.buildTarget){return -1; // x排在前}else if (y.enableTask && x.buildTarget == y.buildTarget){return 1; // y排在前}else{return x.buildTarget.ToString().CompareTo(y.buildTarget.ToString());}}
}

效果图,可以将它锁定在这里,方便后面使用
使用也很简单,选择打包的平台,并设置一些参数。点击开始打包或清理并打包。
注意:打包场景字段是额外添加, 每次打包都会先获取Build Settings里激活的场景,并添加上打包场景中的设置
在这里插入图片描述

其它解释:
有些字段是直接使用Unity的,所以数据是共享的,比如安卓特有的选项,一个地方修改,其它相对应的位置也发生改变。
构建目录格式:打包路径+打包平台+打包子平台+日期(yyMMdd)
为什么添加打包子平台字段,因为我的项目中需要打包服务端(Dedicated Server)

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

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

相关文章

什么是基础镜像

基础镜像是一个在虚拟化技术和容器化技术中广泛使用的概念&#xff0c;具体定义和用途如下&#xff1a; 一、定义 基础镜像&#xff08;Base Image&#xff09;是指操作系统程序及其附加文件的一个复制品&#xff0c;在云服务行业中通常称为系统镜像&#xff08;System Image…

JAVA实现五子棋小游戏(附源码)

文章目录 一、设计来源捡金币闯关小游戏讲解1.1 主界面1.2 黑棋胜利界面1.3 白棋胜利界面 二、效果和源码2.1 动态效果2.2 源代码 源码下载更多优质源码分享 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/145161039 JA…

Flink概述

一、Flink是什么 二、Flink特点 三、Flink vs SparkStreaming 表 Flink 和 Streaming对比 Flink Streaming 计算模型 流计算 微批处理 时间语义 事件时间、处理时间 处理时间 窗口 多、灵活 少、不灵活&#xff08;窗口必须是批次的整数倍&#xff09; 状态 有 …

基于SpringBoot的企业级工位管理系统【源码+文档+部署讲解】

系统介绍 基于SpringBootVue实现的企业级工位管理系统采用前后端分离架构方式&#xff0c;系统设计了管理员、员工两种角色&#xff0c;系统实现了用户登录与注册、个人中心、员工管理、部门信息管理、工位信息管理、使用情况管理、工位分配管理等功能。 技术选型 开发工具&…

【计算机体系结构、微架构性能分析】core 与 uncore 分别是哪一些部分?区分 core 和 uncore

在计算机体系结构中&#xff0c;Core 和 Uncore 是描述处理器内部架构的两个重要概念&#xff0c;尤其在多核处理器中更为常见。 1. Core&#xff08;核心&#xff09; Core 指的是处理器中的计算核心&#xff0c;是执行指令和处理数据的基本单元。每个核心都包含独立的执行单…

数据结构——线性表和顺序表

1、线性表的基本概念 1.1 定义 线性结构是简单且常用的数据结构&#xff0c;而线性表则是一种典型的线性结构 存储数据&#xff0c;最简单&#xff0c;最有效的方法是吧它们存储在一个线性表中 一个线性表是n个元素的有限序列。每个元素在不同的情况下有不同的含义&#xff0c…

Windows图形界面(GUI)-QT-C/C++ - QT 窗口属性

公开视频 -> 链接点击跳转公开课程博客首页 -> ​​​链接点击跳转博客主页 目录 标题栏 基本概念 设置窗口标题 隐藏标题栏 UI编辑器 窗口关闭事件 窗口大小调整事件 窗口移动事件 自定义标题栏 菜单栏 基本概念 设置菜单栏(API) 设置菜单栏(UI) 工具栏 …

Linux系统离线部署MySQL详细教程(带每步骤图文教程)

1、登录官网下载对应的安装包 MySQL :: Developer Zone 2、将压缩包上传到服务器上&#xff0c;这里直接上传到/usr/local路径上 使用sftp工具上传到/usr/local目录上 3、解压压缩包 tar -xf mysql-8.0.39-linux-glibc2.17-x86_64.tar.xz 4、将mysql-8.0.39-linux-glibc2.17…

网络安全技术之计算机安全

计算机安全之访问控制策略 访问控制是网络安全防范和保护的主要策略&#xff0c;它的主要任务是保证网络资源不被非法使用和非常访问。它也是维护网络系统安全、保护网络资源的重要手段。各种安全策略必须相互配合才能真正起到保护作用&#xff0c;但访问控制可以说是保证网络…

leetcode刷题记录(六十一)——73. 矩阵置零

&#xff08;一&#xff09;问题描述 73. 矩阵置零 - 力扣&#xff08;LeetCode&#xff09;73. 矩阵置零 - 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 [http://baike.baidu.com/item/%E5%8E%9F%E5%9…

QT 如何禁止QComboBox鼠标滚轮

一般情况下&#xff0c;QComboBox会相应鼠标的滚轮事件&#xff0c;即当鼠标停靠在QComboBox上方时&#xff0c;滚动鼠标滚轮&#xff0c;QComboBox的选项会发生切换。但这或许并不是我们希望所出现的&#xff0c;尤其是当QComboBox嵌入在QScrollArea中时&#xff0c;用户只是想…

【蓝桥杯】43689.包子凑数

题目描述 小明几乎每天早晨都会在一家包子铺吃早餐。他发现这家包子铺有 &#x1d441; 种蒸笼&#xff0c;其中第 &#x1d456; 种蒸笼恰好能放 &#x1d434;&#x1d456; 个包子。每种蒸笼都有非常多笼&#xff0c;可以认为是无限笼。  每当有顾客想买 &#x1d44b; 个包…

CV与NLP经典大模型解读

一。llm与lora微调策略解读 (1)文本大模型 llama:meta开源语言模型(咱们能负担得起下游任务了)。 lora:绘你模型你也得能训练的动才行(咱们也能微调下游任务)。loradiffusion。 self-instruct:下游任务得规矩些&#xff0c;输入与输出都得有一个标准格式。 peft:将上面三个…

ESP8266-01S的WIFI功能AT指令

1、ATCWMODE——设置wifi模式(STA/AP/STAAP) 设置指令&#xff1a;ATCWMODE<mode> 参数说明&#xff1a;1:station模式 2:sofAP模式 3:stationsofAP模式 查询指令&#xff1a;ATCWMODE? 参数说明&#xff1a;1:station模式 2:sofAP模式 …

Dexie.js内存管理技巧:在大型数据集操作中避免浏览器崩溃

Dexie.js 内存管理技巧&#xff1a;避免浏览器崩溃 在使用 Dexie.js 操作 大型数据集 时&#xff0c;如果不注意内存管理&#xff0c;可能会导致浏览器内存溢出&#xff08;OOM&#xff0c;Out of Memory&#xff09;或崩溃。因此&#xff0c;以下 内存管理技巧 可用于优化性能…

K8S集群常用命令

1&#xff0c;查看pod kubectl get pods -A 查看所有的pod kubectl get pods 这个只查看namespace为default下的pod&#xff0c;也就是只查看默认命名空间下的pod kubectl get pod -A -o wide 查看所有的pod&#xff0c;并且放出的信息更全&#xff08;包含了pod的ip&#xff0…

人机交互(包含推荐软件)

视觉交互、语音交互、笔式交互、触觉交互、虚拟环境交互。 主要的研究方面包括&#xff1a;人机交互界面表示模型与设计方法、可用性工程、可用性评估模型和方法、多模态智能交互技术、智能交互认知技术、语音识别交互、web界面交互设计、移动界面交互设计。 交互设计流程&am…

解锁未来情感科技:AI 机器人 Ropet 搭载的前沿智能黑科技

2025年的国际消费电子产品展览会&#xff08;CES&#xff09;上&#xff0c;一只可爱的“毛绒玩具”成了全场焦点。 当然&#xff0c;这并不是一个单纯的玩偶&#xff0c;而是和《超能陆战队》的大白一样温暖的陪伴机器人。 相信有很多人和小编一样&#xff0c;当年看完《超能…

C++ ranges

C20新增 ranges 新特性 任何可以迭代的对象都可以使用 ranges。头文件&#xff1a;#include 注&#xff1a; std::views是std::ranges::views的别名 常用方法&#xff1a; 1.遍历 正序遍历&#xff1a;for(int i:v) 逆序遍历&#xff1a;for(int i:v|reverse) 2.判断是否为空…

HarmonyOS 鸿蒙 ArkTs(5.0.1 13)实现Scroll下拉到顶刷新/上拉触底加载,Scroll滚动到顶部

HarmonyOS 鸿蒙 ArkTs(5.0.1 13)实现Scroll下拉到顶刷新/上拉触底加载 效果展示 使用方法 import LoadingText from "../components/LoadingText" import PageToRefresh from "../components/PageToRefresh" import FooterBar from "../components/…