【muzzik 分享】原生预览调试!我给Cocos加了个新功能,原生开发者福音

news2025/9/22 1:37:11

前言

一年一度的征稿到了,倒腾点存货,在之前阅读云风大佬文章的时候,发现他的引擎调试机制是在 手机上实时刷新预览,而不是在PC上调试,作为一个 Cocos 原生开发者,我深有体会,主要有以下原因

  • Creator 在原生只能达到大概 95% 的一致性

    例如多 Bundle 脚本引用顺序错误,龙骨/Spine闪退,渲染异常(极少发生)

  • 性能测试

    PC网页可以使用CPU降速达到原生大概的性能,但是并没有真机准确以及不能测试是否发热

  • UI/交互设计

    这个对于经验丰富的团队来说没什么问题,但是对于新团队或者独立开发者是个重要的问题,鼠标并不能准确模拟手指的体验,有可能美术图标小了,也有可能按钮的点击范围小了

所以我在想 Creator 是否能实现原生预览调试呢?既然网页可以,为什么真机不行,于是我完成了它

请添加图片描述

环境

Creator版本:3.6.1

开始实现

  1. 创建一个 Launcher 项目用于加载 Bundle,刚开始我想通过 Launcher 直接加载远程 Bundle 的方式加载原项目预览模式的 Bundle,于是…
    请添加图片描述

  2. 好的,熟悉原生开发的我知道这是 bundle 的配置文件,然后我在网页发现了预览模式加载 Bundle 配置获取的是 config.json 而不是 cc.config.json
    请添加图片描述

  1. 使用 Nodejs 创建一个代理服务器用来转发和修改 Launcher 项目的请求
    1. 创建一个基础的 TS Nodejs项目,并使用 npm i 安装 http-proxy 模块
    2. 使用内置的 http 创建一个服务器,并使用 http-proxy 模块转发请求,代码如下
    http
    	.createServer((req, res) => {
    		// bundle 配置
    		if (req.url?.endsWith("/cc.config.json")) {
    			req.url = req.url.replace("/cc.config.json", "/config.json");
    		}
    
    		proxy.web(req, res, { target: "http://localhost:7456" });
    	}).listen(端口号);
    
  2. 重新尝试,没有config的错误的了,发现有个资源加载失败,搜索一番,发现是Test Bundle 中的脚本
    请添加图片描述

而在原生中 bundle 的脚本都是合并后的 index.js,我们打开调试器看看现在 Test Bundle脚本
请添加图片描述

什么都没有,这是不正常的,正常 Bundle 的 index 脚本包含了全部的脚本源码,所以继续研究

第一个问题:Bundle 脚本不正确

由于我之前无意中逛项目文件夹,发现 项目根目录\temp\programming\packer-driver\targets\preview\import-map.json 文件是记录脚本引用关系的 json 文件
请添加图片描述

于是就可以利用这个文件组装 Bundle 的脚本,代码太多不便展示,步骤简单为

  1. 通过Bundle磁盘路径划分 imports 中的脚本
  2. 通过请求 http://localhost:7456/scripting/x/import路径 拿到脚本源码
  3. 合并脚本源码

第二个问题:脚本加载顺序如何保证?

脚本加载顺序不对会导致 import 的模块出现空的情况

请添加图片描述

在正常编译出的 Bundle 脚本内,System.register("chunks:///_virtual/Bundle名称" 这一行后面其实就脚本的加载顺序,所以我们生成的 Bundle 脚本可以在这里把排序后的脚步名填写进去

排序算法为:

script_ss.sort((va_s, vb_s) => {
    for (
        let k_n = 0, len_n = Math.min(va_s.length, vb_s.length);
        k_n < len_n;
        ++k_n
    ) {
        let a_n = va_s.charCodeAt(k_n);
        let b_n = vb_s.charCodeAt(k_n);
        if (a_n !== b_n) {
            return a_n - b_n;
        }
    }
    return va_s.length - vb_s.length;
});

第三个问题:NPM脚本

最开始尝试了在 Launcher 项目内安装 npm 包,结果没有任何用,因为 System.register 导入的模块名不一致,所以需要在前面生成 Bundle 脚本时将 import 的模块名替换为实际 npm 的模块名

例如 import dayjs from "dayjs"; 导入的模块名是 dayjs,实际为 chunks:///_virtual/index.js,

怎么确定真正的模块名呢?在原项目 编译后的 Bundle 脚本内查看 就知道了

第四个问题:插件脚本

直接将原项目的插件脚本拷贝至 Launcher 项目

资源部分

在你将脚本加载搞完后,你会发现部分资源也会加载失败…

SpriteFrame

请添加图片描述

这里过太久了,忘记当时怎么解决的了,直接贴代码吧,同样放在代理服务器内

if (req.url?.endsWith("@f9941.json")) {
    let data = (
        await axios.get(`http://localhost:${client_port_n}${req.url}`)
    ).data;

    res.end(
        JSON.stringify([
            1,
            [data.content.texture],
            ["_textureSource"],
            ["cc.SpriteFrame"],
            0,
            [data.content],
            [0],
            0,
            [0],
            [0],
            [0],
        ])
    );
    return;
}

AnimationClip

这个比较复杂,一步一步来

  1. 通过请求链接拿到 uuid
				let uuid_s = req.url!.slice(
					req.url!.lastIndexOf("/") + 1,
					req.url!.lastIndexOf(".")
				);
  1. 通过 uuid 判断是否为动画文件
					let suffix_s: string = (
						await axios.get(
							`http://localhost:${client_port_n}/query-extname/${uuid_s}`
						)
					).data;

					// 动画文件
					if (suffix_s === ".cconb") { ... }
  1. 请求 cconb 文件内容并解析后返回
						let cconb: Uint8Array = (
							await axios.get(
								`http://localhost:${client_port_n}` +
									req.url!.slice(0, req.url!.lastIndexOf(".")) +
									suffix_s,
								{
									responseType: "arraybuffer",
								}
							)
						).data;

						res.end(JSON.stringify({
							version: 1,
							document: decodeCCONBinary(cconb).document,
							chunks: [".bin"],
						}));

decodeCCONBinary 函数请拷贝当前版本引擎源码的 ccon.ts 脚本源码

  1. 修改 config.json 的请求返回数据并修改 extensionMap[“.ccon”],这样引擎才会加载 AnimationClip 的Bin 数据,这是正常的 Bundle 配置文件内容,而预览的请求的 config.json 中的数据是空的
    请添加图片描述
			if (req.url?.endsWith("/cc.config.json")) {
				let bundle_config = (
					await axios.get(
						`http://localhost:${client_port_n}${req.url.replace(
							"cc.config.json",
							"config.json"
						)}`
					)
				).data;

				// 录入待加载的 bin 文件
				bundle_config.extensionMap[".ccon"] = [];
				for (const [k_s, v] of Object.entries(
					bundle_config.paths as Record<string, string[]>
				)) {
					if (v[1] === "cc.AnimationClip") {
						bundle_config.extensionMap[".ccon"].push(k_s);
					}
				}

				res.end(JSON.stringify(bundle_config));
				return;
			}
  1. 拦截 bin 文件请求返回 AnimatiomClip 数据
    使用 if (req.url?.endsWith(".bin")) { 拦截,代码和上面 1-3 步一样,只是返回数据为 res.end(decodeCCONBinary(cconb).chunks[0]);

使用准备

代理服务器已经可以正常使用了,但是现在还有一些问题

启动项目

启动时需要清理缓存防止旧内容未刷新

cc.assetManager.cacheManager.clearCache();

原项目

准备一个中转 Bundle,在中转 Bundle 的脚本内重载 loadBundle,IP 为代理服务器电脑的 IP

		let old_load_bundle = cc.assetManager.loadBundle;

		cc.assetManager.loadBundle = function (name: string, ...args_as: any[]) {
			if (!name.startsWith("http")) {
				name = `http://192.168.0.102:8848/assets/${name}`;
			}

			old_load_bundle.call(cc.assetManager, name, ...args_as);
		};

        cc.assetManager.loadBundle("Test", (err, bundle) => {
            if (err) {
                console.log(err);
                return;
            }
			bundle.loadScene("test", (err, scene) => {
                if (err) {
                    console.log(err);
                    return;
                }
				cc.director.runScene(scene);
			});
		});

源码

后续上传至 CocosStore,有意愿的小伙伴自行购买(活动内 20,活动结束 50),另外我会在自己的售后群内抽取 5 位幸运小伙伴获得源码

结语

自动化想法

最近不在游戏行业,所以没有实现,说说自己的想法

  1. 拉取代码后通过(Creator 插件监听刷新 / 文件系统监听 imports-map)
  2. 代理服务器更新代码内容后使用 websocket 通知启动项目重启

写的很差,欢迎批评,不懂就问,只提供思路(涉及付费)

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

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

相关文章

一、Spring基础 --- 基础内容(二) (咕P4)

一、IOC容器 1.1 基础 1.1.1 容器 1、Spring框架的主要功能是通过其核心容器来实现的。2、Spring容器是生成Bean的工厂&#xff0c;它负责创建Bean的实例&#xff0c;并管理其生命周期。所有的组件都被当成Bean处理&#xff0c;例如数据源、Hibernate的SessionFactory、事务管…

【Keil5-报错】

Keil5-报错 ■ 调试烧录出现问题■ 烧录程序失败■ 编译报错 .\Objects\stm32h7_tms.axf: Error: L6218E: Undefined symbol __heap_base (referred from alloc.o).■ Keil5 load 出错■ No Space in execution regions with .ANY selector matching startup ...■ Execution r…

寄快递的省钱小妙招,看看你能知道多少

首先就是从包裹的重量上和体积上&#xff0c;我们都知道快递员上门取件都是需要称重的&#xff0c;我们能做的就是尽量压缩包裹的体积来减少快递的运费价格。然后是使用自己的包装袋来打包行李&#xff0c;快递员的袋子也是需要另外花费的。对于一些不容易损坏的货物来说&#…

基于SVM的时间序列预测模型matlab代码

整理了基于SVM的时间序列预测模型matlab代码&#xff0c; 包含数据集。采用了四个评价指标R2、MAE、MBE、MAPE对模型的进行评价。SVM模型在数据集上表现非常好。 Mean squared error 0.000180613 (regression) Squared correlation coefficient 0.995639 (regression) Mea…

了解单链表

27. 移除元素 - 力扣&#xff08;LeetCode&#xff09; 思路一&#xff1a; 创建新的数组&#xff0c;遍历原数组&#xff0c;将不为val的值放到新数组当中。空间复杂度不为O(1) 思路二&#xff1a;双指针法 我们设置两个指针src&#xff08;源数据&#xff09;和dst&#xf…

MOS管的判别符号记忆与导通条件

参考链接 MOS管的判别与导通条件 (qq.com)https://mp.weixin.qq.com/s?__bizMzU3MDU1Mzg2OQ&mid2247520228&idx1&sn5996780179fbf01f66b5db0c71622ac3&chksmfcef6c86cb98e590e3d3734ee27797bdded17b6b648b3b0d3b1599e8a4496a1fa4e457be6516&mpshare1&…

[CUDA 学习笔记] 矩阵转置算子优化

矩阵转置算子优化 矩阵转置是一种基础的矩阵操作, 即将二维矩阵的行列进行反转. 本文主要围绕行主序的二维单精度矩阵的转置考虑相关的优化. 以下 kernel 笔者均是在 NVIDIA V100 (7.0 算力) 上进行测试的, 且选择矩阵的行列维度大小为 M2300 N1500. Version 0. 朴素实现 _…

流量分组新增两大新规则;Network SDK更新618大促版本;综合报表支持实时新用户指标 | TopOn产品更新

「TopPro 每月产品速递」是由TopOn最新推出的产品专栏&#xff0c;将会以月为周期梳理TopOn最新产品动态&#xff0c;致力于为互联网从业者提供优质服务&#xff0c;引领行业产品发展。 TopPro | 四月产品速递 2023.04.01-04.27 01 流量分组新增两大新规则 // 功能描述 *…

面向AI编程,AI可以为我们做哪些事情

本来这篇文章是2023-10月发出的&#xff0c;放在草稿箱比较久了。今天重新捡起来发下。内容很长&#xff0c;很干。希望对大家有启发&#xff0c;编程路上提升效率。 背景 基本上以前我们出了bug都是百度&#xff0c;但随着AI的出现&#xff0c;对标百度给出的答案。发现AI实在…

python爬虫-------JsonPath(第十九天)

&#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; &#x1f388;&#x1f388;所属专栏&#xff1a;python爬虫学习&#x1f388;&#x1f388; ✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天…

Pytorch中nn.Linear使用方法

nn.Linear定义一个神经网络的线性层&#xff1a; torch.nn.Linear(in_features, # 输入的神经元个数out_features, # 输出神经元个数biasTrue # 是否包含偏置)nn.Linear其实就是对输入&#xff08;n表示样本数量&#xff0c;i表示样本特…

国产低代码工具,轻松搞定数据迁移

在日常的业务系统升级或者数据维护过程中&#xff0c;数据迁移是各个企业用户不得不面临的问题&#xff0c;尤其是数据迁移过程中要保障数据完整性、统一性和及时性&#xff0c;同时也需要注意源数据中的数据质量问题&#xff0c;比如缺失、无效、错误等问题&#xff0c;需要在…

Kubernetes中安装部署Nacos集群

目录 1、Nacos安装包的准备 1.1 下载安装包 1.2 解压安装包 1.3 修改配置文件 application.properties 1.4 bin目录下创建 docker-startup.sh 1.5 将nacos-server-1.2.1目录打包成nacos-server-1.2.1.tar.gz 2、 nacos镜像制作 2.1 Dockerfile文件编写 2.2 制作镜像…

单片机入门还能从51开始吗?

选择从51单片机开始入门还是直接学习基于ARM核或RISC核的单片机&#xff0c;取决于学习目标、项目需求以及个人兴趣。每种单片机都有其特定的优势和应用场景&#xff0c;了解它们的特点可以帮助你做出更合适的选择。 首先&#xff0c;我们说一下51单片机的优势&#xff1a; 成熟…

外包干了17天,技术倒退明显

先说情况&#xff0c;大专毕业&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近6年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落&#xff01; 而我已经在一个企业干了四年的功能…

【石上星光】context,go的上下文存储并发控制之道

目录 1 引言2 What&#xff1f;3 How&#xff1f; 3.1 用法一、上下文数据存储3.2 用法二、并发控制 3.2.1 场景1 主动取消3.2.2 场景2 超时取消 3.3 用法三、创建一个空Context&#xff08;emptyCtx&#xff09; 4 Why&#xff1f; 4.1 go中的上下文思想 4.1.1 上下文是什么…

技术小课堂:100%CC防护是怎么实现的?

大家好&#xff0c;今天我们深入探讨的是如何有效地实现CC攻击的100%防护&#xff0c;以及传统防护手段存在的局限性和我们的定制化解决方案的优势。 传统的CC防护措施通常依赖于全局性的访问频率控制或在防火墙级别设置固定的访问次数限制。这种方式看似简单直接&#xff0c;…

安全大脑与盲人摸象

21世纪是数字科技和数字经济爆发的时代&#xff0c;互联网正从网状结构向类脑模型进行进化&#xff0c;出现了结构和覆盖范围庞大&#xff0c;能够适应不同技术环境、经济场景&#xff0c;跨地域、跨行业的类脑复杂巨型系统。如腾讯、Facebook等社交网络具备的神经网络特征&…

[方案实操|数据技术]数据要素十大创新模式(1):基于区块链的多模态数据交易服务平台

“ 区块链以其公开共享、去中心化、不可篡改、可追溯和不可抵赖等优势&#xff0c;吸引了包括金融业、医疗业和政府部门等众多利益相关方的极大兴趣&#xff0c;被认为是解决数据安全交换问题的合适方案。” 武汉东湖大数据科技股份有限公司凭借基于区块链的多模态数据交易服务…

交换机的基本原理与配置_实验案例一:交换机的初始配置

1、实验环境 实验用具包括一台Cisco交换机&#xff0c;一台PC&#xff0c;一根Console 线缆。 2、需求描述 如图5.17所示&#xff0c;实验案例一的配置需求如下。 通过PC连接并配置一台Cisco交换机。在交换机的各个配置模式之间切换。将交换机主机的名称改为BDON 3、推荐步…