Unity之一键创建自定义Package包

内容将会持续更新,有错误的地方欢迎指正,谢谢!
 

Unity之一键创建自定义Package包
     
TechX 坚持将创新的科技带给世界!

拥有更好的学习体验 —— 不断努力,不断进步,不断探索
TechX —— 心探索、心进取!

助力快速掌握 自定义Package 快速创建

为初学者节省宝贵的学习时间,避免困惑!


前言:

  在之前的文章从零开始创建Unity自定义包Package:一步一步实现您的功能,我已经详细的介绍了该如何一步一步的去创建自己的自定义Package包,但是我相信有的小伙伴还是觉得文章很长不想看,或者觉得创建一个自定义包很麻烦,又要创建包,又要导入包的。

  今天小伙伴们可以轻松的去做这件事了,你可以直接一键的去生成包和导入包到Unity,真正的做到了省心、省时、省力,接下来就让我们一起来看怎么实现的吧。

TechX 教程效果:

在这里插入图片描述


文章目录

  • 一、绘制package创建器面板
  • 二、创建包
    • 1、创建文件夹和Assembly Definition
    • 2、创建包清单文件 (package.json)
    • 3、创建CHANGELOG.md
    • 4、创建README.md
  • 三、安装包
  • 四、项目地址


一、绘制package创建器面板


创建器面板的绘制基本上是package.json文件中的内容,包含大多数的包清单中的内容,包含:包名,包版本,包展示名,包描述,Unity版本,Unity发布版本号,文档地址,改变日志地址,证书地址,依赖列表,关键词列表,作者信息,案例列表等。

其中还包含了创建包时的选项,包含是否创建Scripts文件夹,是否创建Tests文件夹,是否创建CHANGELOG文件,是否创建ReadMe文件。

public class PackageCreatorWindow : EditorWindow
{
	private bool isCreteScriptsFolder = true;
	private bool isCreteTestsFolder = false;
	private bool isCreateChangeLog = true;
	private bool isCreateReadme = true;
	
	private string packageName = "";
	private string version = "";
	private string displayName = "";
	private string description = "";
	private string unity = "";
	private string unityRelease = "";
	private string documentationUrl = "";
	private string changelogUrl = "";
	private string licensesUrl = "";
	private List<Dependency> dependencies = new List<Dependency>();
	private List<string> keywords = new List<string>();
	private Author author = new Author();
	private List<Sample> samples = new List<Sample>();
	
	private ReorderableList keywordsReorderableList;
	private ReorderableList samplesReorderableList;
	private ReorderableList dependenciesReorderableList;
	
	private void OnGUI()
	{
	    DrawGUI();
	}

	private void DrawGUI()
	{
	    GUILayout.Space(5f);
	
	    GUILayout.Label("Package Config", new GUIStyle { fontSize = 20, padding = new RectOffset() { left = 5 }, fontStyle = FontStyle.Bold, normal = { textColor = Color.white } }); ;
	
	    GUILayout.Space(5f);
	
	    scrollPos = EditorGUILayout.BeginScrollView(scrollPos,EditorStyles.helpBox);
	
	    isCreteScriptsFolder = EditorGUILayout.ToggleLeft("Is Crete Scripts Folder", isCreteScriptsFolder);
	 	isCreteTestsFolder = EditorGUILayout.ToggleLeft("Is Crete Tests Folder", isCreteTestsFolder);
		isCreateChangeLog = EditorGUILayout.ToggleLeft("Is Create ChangeLog File", isCreateChangeLog);
		isCreateReadme = EditorGUILayout.ToggleLeft("Is Create ReadMe File", isCreateReadme);
		packageName = EditorGUILayout.TextField("Package Name *", packageName);
		version = EditorGUILayout.TextField("Version *", version);
		displayName = EditorGUILayout.TextField("Display Name *", displayName);
		description = EditorGUILayout.TextArea(description, GUILayout.Height(50));
		unity = EditorGUILayout.TextField("Unity Version *", unity);
		unityRelease = EditorGUILayout.TextField("Unity Release *", unityRelease);
		documentationUrl = EditorGUILayout.TextField("Documentation URL", documentationUrl);
		changelogUrl = EditorGUILayout.TextField("Changelog URL", changelogUrl);
		licensesUrl = EditorGUILayout.TextField("Licenses URL", licensesUrl);
		dependenciesReorderableList.DoLayoutList();
		keywordsReorderableList.DoLayoutList();
		autorToogleGroup = EditorGUILayout.BeginFoldoutHeaderGroup(autorToogleGroup, "Author");
		if (autorToogleGroup)
		{
		    EditorGUI.indentLevel += 1;
		    author.name = EditorGUILayout.TextField("Name", author.name);
		    author.email = EditorGUILayout.TextField("Email", author.email);
		    author.url = EditorGUILayout.TextField("Url", author.url);
		    EditorGUI.indentLevel -= 1;
		}
		EditorGUILayout.EndFoldoutHeaderGroup();
		samplesReorderableList.DoLayoutList();
	    EditorGUILayout.EndScrollView();
	
	    //创建之前要验证面板信息
	    if (GUILayout.Button("Create Package"))
	    {
	        string selectPath = EditorUtility.OpenFolderPanel("Select Folder for New Package", "", "");
	        bool isSuccess = CreateNewPackage(selectPath, packageName, out string packagePath);
	        if (isSuccess == false) return;
	        InstallPackage(selectPath, packagePath);
	    }
	}
}


二、创建包


1、创建文件夹和Assembly Definition


为创建的包创建一些需要的文件夹,比如Scripts/Editor、Scripts/Runtime、Tests/Editor、Tests/Runtime文件夹。
Scripts/Editor文件夹包含编辑器使用的功能,放置的脚本只在编辑器环境中使用。
Scripts/Runtime文件夹包含游戏运行时使用的功能,放置的脚本将在游戏运行时执行。
Tests/Editor用于编辑器测试,Tests/Runtime用于运行时测试。

/// <summary>
/// 创建包文件夹
/// </summary>
private void CreatePackageFolder(string pacakgePath, string packageName)
{
	//TODO 创建Scripts文件夹。。。。
    string scriptsFolderPath = Path.Combine(pacakgePath, "Scripts");
    Directory.CreateDirectory(scriptsFolderPath);

    //创建Editor和Runtime文件夹
    string editorFolderPath = Path.Combine(scriptsFolderPath, "Editor");
    string runtimeFolderPath = Path.Combine(scriptsFolderPath, "Runtime");

    Directory.CreateDirectory(editorFolderPath);
    Directory.CreateDirectory(runtimeFolderPath);

    // Create .asmdef files
    //这里的asmdef的文件的包名是否首字母大写??
    string editorAsmdefPath = Path.Combine(editorFolderPath, $"{packageName}.Editor.asmdef");
    string runtimeAsmdefPath = Path.Combine(runtimeFolderPath, $"{packageName}.Runtime.asmdef");

    AsmdefConfigProcess.CreateAsmdefContent(editorAsmdefPath, true);
    AsmdefConfigProcess.CreateAsmdefContent(runtimeAsmdefPath, false);
    
    //TODO 创建Tests文件夹。。。。
    string testsFolderPath = Path.Combine(pacakgePath, "Tests");
    Directory.CreateDirectory(testsFolderPath);

    string testseEditorFolderPath = Path.Combine(testsFolderPath, "Editor");
    string testseRuntimeFolderPath = Path.Combine(testsFolderPath, "Runtime");

    Directory.CreateDirectory(testseEditorFolderPath);
    Directory.CreateDirectory(testseRuntimeFolderPath);

    string testseEditorAsmdefPath = Path.Combine(testseEditorFolderPath, $"{packageName}.Editor.Tests.asmdef");
    string testseRuntimeAsmdefPath = Path.Combine(testseRuntimeFolderPath, $"{packageName}.Runtime.Tests.asmdef");

    AsmdefConfigProcess.CreateAsmdefContent(testseEditorAsmdefPath, true);
    AsmdefConfigProcess.CreateAsmdefContent(testseRuntimeAsmdefPath, false);
}

在每个文件夹创建完成之后,我们都需要在文件夹中定义一个程序集文件,注意在不同的文件夹中,程序集文件的名称是不一样的,同时也要注意,对于运行时和编辑器下的程序集平台也是不一样的,运行时的平台一般是Any Platform,而编辑器的平台是Editor。

public class AsmdefConfig
{
    public string name;
    public string rootNamespace;
    public List<string> references;
    public List<string> includePlatforms;
    public List<string> excludePlatforms;
    public bool allowUnsafeCode;
    public bool overrideReferences;
    public List<string> precompiledReferences;
    public bool autoReferenced;
    public List<string> defineConstraints;
    public List<string> versionDefines;
    public bool noEngineReferences;
}

public class AsmdefConfigProcess
{
    /// <summary>
    /// 创建.asmdef
    /// </summary>
    /// <param name="path">创建的位置</param>
    /// <param name="isEditor">适用于运行时还是编辑器下</param>
    public static void CreateAsmdefContent(string filePath, bool isEditor)
    {
        string fileName = Path.GetFileNameWithoutExtension(filePath) ;
        AsmdefConfig asmdefClass = new AsmdefConfig();
        asmdefClass.name = fileName;
        asmdefClass.rootNamespace = "";
        asmdefClass.references = new List<string>();
        asmdefClass.includePlatforms = isEditor ? new List<string> { "Editor" } : new List<string>();
        asmdefClass.excludePlatforms = new List<string>();
        asmdefClass.allowUnsafeCode = false;
        asmdefClass.overrideReferences = false;
        asmdefClass.precompiledReferences = new List<string>();
        asmdefClass.autoReferenced = true;
        asmdefClass.defineConstraints = new List<string>();
        asmdefClass.versionDefines = new List<string>();
        asmdefClass.noEngineReferences = false;

        JObject asmdefJson = JObject.FromObject(asmdefClass);

        File.WriteAllText(filePath, asmdefJson.ToString());
    }
}

2、创建包清单文件 (package.json)


每个Unity Package都必须包含一个名为package.json的清单文件。这个文件包含了有关包的元信息,如名称、版本、依赖项等。

/// <summary>
/// 创建package.json文件
/// </summary>
private void CreatePackageFile(string pacakgePath)
{
    // Create package.json
    PackageConfigProcess.CreatePackageJson(pacakgePath, GetPackageJsonContent());
}

这里定义了包清单的一些相关类型,当需要创建package.json文件时,从面板上获取到包相关信息,并生成PackageConfig实例,将该实例转换成JSON字符串写入到json文件中。

[System.Serializable]
public class Author
{
    public string name = "";
    public string email = "";
    public string url = "";
}

[System.Serializable]
public class Dependency
{ 
    public string packageName;
    public string version;
}

[System.Serializable]
public class Sample
{
    public string displayName;
    public string description;
    public string path;
}

public class PackageConfig
{
    public string name = "";
    public string version = "";
    public string displayName = "";
    public string description = "";
    public string unity = "";
    public string unityRelease = "";
    public string documentationUrl = "";
    public string changelogUrl = "";
    public string licensesUrl = "";
    public JObject dependencies = new JObject();
    public List<string> keywords = new List<string>();
    public Author author = new Author();
    public List<Sample> samples = new List<Sample>();
}

public class PackageConfigProcess
{
    public static void CreatePackageJson(string path, PackageConfig packageConfig)
    {
        JObject packageConfigJson = JObject.FromObject(packageConfig);

        string fullPath = Path.Combine(path, $"package.json");

        File.WriteAllText(fullPath, packageConfigJson.ToString());
    }
}

3、创建CHANGELOG.md


CHANGELOG.md文件是版本信息改变的日志文件,建议在每次发布新版本时更新CHANGELOG.md文件。在文件中记录新增功能、改进和错误修复。

/// <summary>
/// 创建CHANGELOG.md文件
/// </summary>
private void CreateChangeLogFile(string pacakgePath)
{
    // Create CHANGELOG.md
    string changeLogPath = Path.Combine(pacakgePath, "CHANGELOG.md");
    File.WriteAllText(changeLogPath, "# Changelog\nAll notable changes to this package will be documented in this file.\n\n");
}

4、创建README.md


README.md文件是关于该插件的介绍和如何使用的。

/// <summary>
/// 创建README.md文件
/// </summary>
private void CreateReadMeFile(string pacakgePath)
{
    // Create README.md
    string readmePath = Path.Combine(pacakgePath, "README.md");
    File.WriteAllText(readmePath, $"# {Path.GetFileName(pacakgePath)}\n\n");
}


三、安装包


在包创建完成后,会把包创建到本地的某个文件夹中,但是这个时候并没有把包安装到Unity中,按照一般的方法,在创建完成包后,可以通过Package Manager中的Add package form disk选项去文件夹中选择包的package.json文件来安装本地包。

但是在这里我们在创建完成包后,直接根据包的路径来,直接使用代码来模拟Add package form disk选择package.json文件来安装包。

注意:当我们把包直接创建到工程的Packages文件中时,那么我们就不需要通过代码来添加包到工程中,因为Unity会自动完成这一步。

/// <summary>
/// 安装包
/// </summary>
/// <param name="creteResult"></param>
/// <param name="selectPath"></param>
/// <param name="packagePath"></param>
private void InstallPackage(string selectPath, string packagePath)
{
    //如果直接创建到了Packages文件加中,那么就不需要手动添加到工程中,Unity会自动添加
    if (File.Exists(Path.Combine(selectPath, "manifest.json"))) return;

    //TODO 添加包到工程中
    PackageInstaller.InstallPackageFromDisk(packagePath);
}

从本地安装包的方式有两种,一种是从文件夹安装,要求包含package.json文件,并且符合包清单的条件,一种是通过.tgz压缩包的方式安装包。

这两种包在安装时都需要在路径前"file:"才能正确的安装包。

public class PackageInstaller
{
    /// <summary>
    /// 从本地路径安装包
    /// 1、可以通过本地文件夹安装包,格式file:pathtopackagefolder,如file:E:/UPMProject/UPM/com.fxb.test
    /// 2、从.tgz文件安装包,格式file:pathtopackage.tgz,如file:E:/UPMProject/UPM/com.fxb.test.tgz
    /// </summary>
    /// <param name="packagePath"></param>
    public static void InstallPackageFromDisk(string packagePath)
    {
        //从本地文件夹安装包
        if (Directory.Exists(packagePath))
        {
            // 构造package.json文件的完整路径
            string packageJsonPath = Path.Combine(packagePath, "package.json");

            // 检查package.json文件是否存在
            if (!File.Exists(packageJsonPath))
            {
                Debug.LogError("The provided folder does not contain a valid 'package.json' file and is not a valid Unity package.");
                return;
            }
        }
        //从.tgz文件安装包
        else if (File.Exists(packagePath))
        {
            if (!packagePath.EndsWith(".tgz"))
            {
                Debug.LogError($"{packagePath} file is not a valid Unity package.");
                return;
            }
        }
        else
        {
            Debug.LogError($"The package at path {packagePath} does not exist.");
            return;
        }

        // 构建正确的标识符
        string identifier = $"file:{packagePath}";
        // 如果存在package.json,那么这是一个有效的包,可以继续安装
        AddRequest request = Client.Add(identifier);
        CallbackFunction onAddUpdate = null;
        onAddUpdate = () =>
        {
            if (request.IsCompleted)
            {
                if (request.Status == StatusCode.Success)
                    Debug.Log($"Package from {packagePath} installed successfully.");
                else
                    Debug.LogError($"Failed to install package from {packagePath}: {request.Error.message}");

                // 移除更新回调
                EditorApplication.update -= onAddUpdate;
            }
        };

        // 注册更新事件
        EditorApplication.update += onAddUpdate;
    }
}


四、项目地址


以下是项目地址,已经整理成了Package包,有需要的小伙伴门可以自取:

https://gitcode.com/CTLittleNewbie/com.fxb.unitypackagecreator_v1.0.0/overview





TechX —— 心探索、心进取!

每一次跌倒都是一次成长

每一次努力都是一次进步


END
感谢您阅读本篇博客!希望这篇内容对您有所帮助。如果您有任何问题或意见,或者想要了解更多关于本主题的信息,欢迎在评论区留言与我交流。我会非常乐意与大家讨论和分享更多有趣的内容。
如果您喜欢本博客,请点赞和分享给更多的朋友,让更多人受益。同时,您也可以关注我的博客,以便及时获取最新的更新和文章。
在未来的写作中,我将继续努力,分享更多有趣、实用的内容。再次感谢大家的支持和鼓励,期待与您在下一篇博客再见!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【html网页页面007】html+css制作旅游主题内蒙古网页制作含注册表单(4页面附效果及源码)

旅游家乡主题网页制作 &#x1f964;1、写在前面&#x1f367;2、涉及知识&#x1f333;3、网页效果&#x1f308;4、网页源码4.1 html4.2 CSS4.3 源码获取 &#x1f40b;5、作者寄语 &#x1f964;1、写在前面 家乡网站主题内蒙古的网页 一共4个页面 网页使用htmlcss制作页面…

Ardupilot开源无人机之Geek SDK讨论

Ardupilot开源无人机之Geek SDK讨论 1. 源由2. 假设3. 思考3.1 结构构型3.2 有限资源3.3 软硬件构架 4.Ardupilot构架 - 2024kaga Update5. 讨论5.1 话题1&#xff1a;工作模式5.2 话题2&#xff1a;关键要点5.3 话题3&#xff1a;产品设计 6. Geek SDK - OpenFire6.1 开源技术…

JavaWeb——Maven高级

11.1. 分模块设计与开发 将项目按照功能拆分成若干个子模块&#xff0c;方便项目的管理维护、扩展&#xff0c;也方便模块之间的互相调用&#xff0c;资源共享。 11.2. 继承与聚合 11.2.1. 继承 父工程的的打包方式必须为pom 实现步骤 11.2.2. 版本锁定 dependencyManagemen…

Python中的实用工具JSON解析

对于Python不熟悉的同学&#xff0c;建议从本专栏第一篇开始观看 https://blog.csdn.net/qq_20330595/category_12844705.html 先上效果图 代码 import threading import tkinter as tk import json from tkinter import scrolledtext import tkinter.filedialog as filedialo…

医学临床机器学习中算法公平性与偏差控制简析

摘要 随着医疗领域中数据的不断积累和计算能力的提升&#xff0c;临床机器学习技术发展迅速&#xff0c;但算法不公平性和偏差问题凸显。本文深入探讨了临床机器学习算法公平性的重要性、概念与定义、在临床应用中的影响、偏差来源、降低偏差方法及提升公平性策略。通过对不同…

【数据结构】二叉搜索树(二叉排序树)

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;数据结构 目录 前言 一、什么是二叉搜索树 二、二叉搜索树的实现 节点 属性和接口的声明 插入 查找 删除 拷贝构造 析构 中序遍历 三、二叉搜索树的…

如何启用本机GPU硬件加速猿大师播放器网页同时播放多路RTSP H.265 1080P高清摄像头RTSP视频流?

目前市面上主流播放RTSP视频流的方式是用服务器转码方案&#xff0c;这种方案的好处是兼容性更强&#xff0c;可以用于不同的平台&#xff0c;比如&#xff1a;Windows、Linux或者手机端&#xff0c;但是缺点也很明显&#xff1a;延迟高、播放高清或者同时播放多路视频视频容易…

乘积求导法则、除法求导法则和链式求导法则

乘积求导法则、除法求导法则和链式求导法则 1. Constant multiples of functions (函数的常数倍)2. Sums and differences of functions (函数和与函数差)3. Products of functions via the product rule (通过乘积法则求积函数的导数)4. Quotients of functions via the quoti…

2个GitHub上最近比较火的Java开源项目

1. SpringBlade 微服务架构 标题 SpringBlade 微服务架构 摘要 SpringBlade 是一个由商业级项目升级优化而来的微服务架构&#xff0c;采用Spring Boot 3.2、Spring Cloud 2023等核心技术构建&#xff0c;遵循阿里巴巴编码规范&#xff0c;提供基于React和Vue的两个前端框架&am…

Ubuntu 安装 MariaDB

安装 MariaDB具体步骤 1、更新软件包索引&#xff1a; sudo apt update2、安装 MariaDB 服务器&#xff1a; sudo apt install mariadb-server3、启动 MariaDB 服务&#xff08;如果未自动启动&#xff09;&#xff1a; sudo systemctl start mariadb4、设置 MariaDB 开机启…

一体化数据安全平台uDSP 入选【年度创新安全产品 TOP10】榜单

近日&#xff0c;由 FreeBuf 主办的 FCIS 2024 网络安全创新大会在上海隆重举行。大会现场揭晓了第十届 WitAwards 中国网络安全行业年度评选获奖名单&#xff0c;该评选自 2015 年举办以来一直饱受赞誉&#xff0c;备受关注&#xff0c;评选旨在以最专业的角度和最公正的态度&…

相同的二叉树

给你两棵二叉树的根节点 p 和 q &#xff0c;编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同&#xff0c;并且节点具有相同的值&#xff0c;则认为它们是相同的。 示例 1&#xff1a; 输入&#xff1a;p [1,2,3], q [1,2,3] 输出&#xff1a;true示例 2&…

百度地图JSAPI WebGL v1.0类参考

百度地图JSAPI WebGL v1.0类参考 核心类 Map 此类是地图API的核心类&#xff0c;用来实例化一个地图。请注意WebGL版本的地图API的命名空间是BMapGL。 示例&#xff1a;const map new BMapGL.Map(container); 构造函数描述Map(container: String | HTMLElement, opts: Map…

【k8s】监控metrics-server

metrics-server介绍 Metrics Server是一个集群范围的资源使用情况的数据聚合器。作为一个应用部署在集群中。Metric server从每个节点上KubeletAPI收集指标&#xff0c;通过Kubernetes聚合器注册在Master APIServer中。为集群提供Node、Pods资源利用率指标。 就像Linux 系统一样…

AI 声音:数字音频、语音识别、TTS 简介与使用示例

在现代 AI 技术的推动下&#xff0c;声音处理领域取得了巨大进展。从语音识别&#xff08;ASR&#xff09;到文本转语音&#xff08;TTS&#xff09;&#xff0c;再到个性化声音克隆&#xff0c;这些技术已经深入到我们的日常生活中&#xff1a;语音助手、自动字幕生成、语音导…

ARM CCA机密计算安全模型之硬件强制安全

安全之安全(security)博客目录导读 [要求 R0004] Arm 强烈建议所有 CCA 实现都使用硬件强制的安全(CCA HES)。本文件其余部分假设系统启用了 CCA HES。 CCA HES 是一个可信子系统的租户——一个 CCA HES 主机(Host),见下图所示。它将以下监控安全域服务从应用处理元件(P…

matlab显示sin二维图

1&#xff0c;新建脚本 2、保存脚本 3、脚本命令&#xff1a;clc 清除 脚本命令的信息 clrear all 清除全部 4工作区内容&#xff1a;变量啥的 x0:0.001:2*pi%% 开始 精度 中值 ysin(x) y1cos(x) figure%%产生一个屏幕 plot(x,y)%%打印坐标 title(ysin(x))%%标题 xlabel(…

一万台服务器用saltstack还是ansible?

一万台服务器用saltstack还是ansible? 选择使用 SaltStack 还是 Ansible 来管理一万台服务器&#xff0c;取决于几个关键因素&#xff0c;如性能、扩展性、易用性、配置管理需求和团队的熟悉度。以下是两者的对比分析&#xff0c;帮助你做出决策&#xff1a; SaltStack&…

Flutter 1.2:flutter配置gradle环境

1、在android的模块中进行gradle环境配置 ①在 gradle-wrapper.properties文件中将url配置为阿里云镜像&#xff0c;因为gradle的服务器在国外&#xff0c;国内下载非常慢&#xff0c;也可在官网进行下载 gradle版本下载 gradle版本匹配 阿里云镜像gradle下载 可以通过复制链…

vue 2 父组件根据注册事件,控制相关按钮显隐

目标效果 我不注册事件&#xff0c;那么就不显示相关的按钮 注册了事件&#xff0c;才会显示相关内容 实现思路 组件在 mounted 的时候可以拿到父组件注册监听的方法 拿到这个就可以做事情了 mounted() {console.log(this.$listeners, this.$listeners);this.show.search !…