From df15648a62d868e450d8f91045c42f140de5ee85 Mon Sep 17 00:00:00 2001
From: liujiangnan <695541723@qq.com>
Date: Thu, 3 Nov 2022 09:03:18 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E6=9B=BF=E6=8D=A2UUI?=
 =?UTF-8?q?D=E7=9A=84=E5=B7=A5=E5=85=B7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .DS_Store                               | Bin 10244 -> 14340 bytes
 README.md                               |  10 ++
 packages/replace-uuid/main.js           |  41 ++++++
 packages/replace-uuid/package-lock.json |  30 +++++
 packages/replace-uuid/package.json      |  15 +++
 packages/replace-uuid/util/file.js      | 164 ++++++++++++++++++++++++
 packages/replace-uuid/util/uuidUtils.js | 106 +++++++++++++++
 7 files changed, 366 insertions(+)
 create mode 100644 packages/replace-uuid/main.js
 create mode 100644 packages/replace-uuid/package-lock.json
 create mode 100644 packages/replace-uuid/package.json
 create mode 100644 packages/replace-uuid/util/file.js
 create mode 100644 packages/replace-uuid/util/uuidUtils.js

diff --git a/.DS_Store b/.DS_Store
index 29750aff4fa9bef62a6da7247c09d823af66f858..dae9c7d0dcdc21ba5d17ba2e3a4c0152f1cf5af3 100644
GIT binary patch
delta 1270
zcmd5+O=}ZT6g`tpC#g>D6be?F!ayT#(jhIWZJ`^*EL;d;e}HC^cKR{N<WmbpW>Z|W
zt1x^2f`lx@oqxhV;2&@$*i}4tY<1pf(4~Pl@4d;n=iYnnNzR_0wQK;|!+w1YDDjx%
zlHD@-cmvqxz`nOU#f!$3=i=D{>e#~x92}rGXs<-2g1#vLo$Ce;(M$r+fdAMJYOWu+
z{GQR7Pu!hx{28_@*-<v9=fXL@oW&8ks39Q5K8ZZ$kT<-m6nH@N+aDA>0rO~~%E)6r
zJyy30pHXt3#PCjK2w|ouCIo8BY9K{ZQ+L%;wTr*u-B;a~8!cJq3+3&#qP@Pk^}1-E
zZm*Y$cKLoe`e1E@zvXzj+iChi(<8SiFSU2r@DW?Dp*N{%?J`wMmT`T!6zh;OAE=dQ
zggq8nACG}i=62o)XYdRa%Kr#YxI3I~JryO>O^zl<<~`Qbi=E*irH_nKyOkK_ERhpU
zu$VLwIK%7EVf)h9726tgK=&%;A5vW#k4SN|D@Cad2<tCYWLn=slcILmM3tolJUKMD
zBW0?Qu{ExY9rNqNiLkvCPAs9~_G8{g3Mb<t&JcAt0Bv43Hcb99q=p8bvz{j1-skwL
z=%}&r@P6iq-siplcywQlJJYdXDBa{<N&W*3+h3-lxx(s<`23@wq8)Q7dQr$uZ^gG(
PVK7=*_?)@>Ps)4;lJQ5Q

delta 156
zcmZoEXbF&DU|?W$DortDU{C-uIe-{M3-C-V6q~3gIoZI3MH0wo-~wVspg2QuK~heB
z5|DQ?sbJ$pGxmuOayPScuy8PPO^#FevH6}NBirUAAxXB4S6(s+GJ~`NP2>g=t{_u4
rUi{8Hncqa0kzuk4kMiUM6LwAwkP4vD29tA4CT_m1%EB}`N$5WSy=Wrk

diff --git a/README.md b/README.md
index 527d207..8ce20d6 100644
--- a/README.md
+++ b/README.md
@@ -57,10 +57,20 @@ npm start
 
 * 下载模板调试专用app 
 
+安卓下载:
+
 http://download-iplayabc.oss-cn-beijing.aliyuncs.com/iDebugABC.apk
 
 ![avatar](http://staging-teach.cdn.ireadabc.com/084f2f95-8213-4c5a-8c46-b194819d7677.png)
 
+
+iOS下载:
+
+由于调试APP没有上架App Store 所以需要先获取手机的UDID 发送给我们的技术支持,加入后才可以扫码下载安装
+获取UDID:https://www.pgyer.com/tools/udid
+下载iOS: https://www.pgyer.com/gS0X
+
+
 * 启动本地服务
 
 ```
diff --git a/packages/replace-uuid/main.js b/packages/replace-uuid/main.js
new file mode 100644
index 0000000..d5df2e0
--- /dev/null
+++ b/packages/replace-uuid/main.js
@@ -0,0 +1,41 @@
+var fs = require('fs-extra');
+var file = require('./util/file');
+
+module.exports = {
+    load() {
+    },
+
+    unload() {
+    },
+
+    replaceDirUuid: function (path, dbpath) {
+        Editor.log('开始处理:' + path);
+        file.findDirUuid(path);
+        file.replaceDirUuid(path);
+
+        Editor.log('开始刷新:' + dbpath);
+        Editor.assetdb.refresh(dbpath, function (err, results) {
+            Editor.log('资源刷新完成, 请重新打开该项目工程!');
+        });
+    },
+
+    messages: {
+        'replace'() {
+            var uuids = Editor.Selection.curSelection('asset');
+            uuids.forEach((uuid) => {
+                var dir_path = Editor.assetdb._uuid2path[uuid];
+                if (fs.existsSync(dir_path)) {
+                    this.replaceDirUuid(dir_path, Editor.assetdb.uuidToUrl(uuid));
+                }
+            });
+        },
+        'replace-path': function (event, dir_path, refresh_path) {
+            if (fs.existsSync(dir_path)) {
+                this.replaceDirUuid(dir_path, refresh_path); // Editor.assetdb.fspathToUrl(refresh_path)
+                if (event.reply) {
+                    event.reply(null, null);
+                }
+            }
+        },
+    },
+}
\ No newline at end of file
diff --git a/packages/replace-uuid/package-lock.json b/packages/replace-uuid/package-lock.json
new file mode 100644
index 0000000..fa80372
--- /dev/null
+++ b/packages/replace-uuid/package-lock.json
@@ -0,0 +1,30 @@
+{
+    "name": "replace-uuid",
+    "version": "0.0.1",
+    "lockfileVersion": 2,
+    "requires": true,
+    "packages": {
+        "": {
+            "version": "0.0.1",
+            "dependencies": {
+                "node-uuid": "1.4.8"
+            }
+        },
+        "node_modules/node-uuid": {
+            "version": "1.4.8",
+            "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz",
+            "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=",
+            "deprecated": "Use uuid module instead",
+            "bin": {
+                "uuid": "bin/uuid"
+            }
+        }
+    },
+    "dependencies": {
+        "node-uuid": {
+            "version": "1.4.8",
+            "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz",
+            "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc="
+        }
+    }
+}
diff --git a/packages/replace-uuid/package.json b/packages/replace-uuid/package.json
new file mode 100644
index 0000000..f8f796c
--- /dev/null
+++ b/packages/replace-uuid/package.json
@@ -0,0 +1,15 @@
+{
+    "name": "replace-uuid",
+    "version": "0.0.1",
+    "description": "replace-uuid",
+    "author": "Cocos Creator",
+    "main": "main.js",
+    "main-menu": {
+        "i18n:MAIN_MENU.package.title/replace-uuid": {
+            "message": "replace-uuid:replace"
+        }
+    },
+    "dependencies": {
+        "node-uuid": "1.4.8"
+    }
+}
diff --git a/packages/replace-uuid/util/file.js b/packages/replace-uuid/util/file.js
new file mode 100644
index 0000000..8635c74
--- /dev/null
+++ b/packages/replace-uuid/util/file.js
@@ -0,0 +1,164 @@
+/**
+ * 一、建立目录中所有meta文件中uuid和新生成uuid的映射关系
+ * 二、替换目录中指定类型文件中的uuid成新的uuid
+ */
+var fs = require("fs-extra");
+var path = require("path");
+var uuidUtils = require("./uuidUtils");
+var uuidMap = {};
+var Reg_Uuid = /^[0-9a-fA-F-]{36}$/;
+module.exports = {
+    /**
+     * 递归目录找到所有meta文件的uuid
+     * 参考 https://docs.cocos.com/creator/manual/zh/advanced-topics/meta.html
+     */
+    findDirUuid: function (dir) {
+        var stat = fs.statSync(dir);
+        if (!stat.isDirectory()) {
+            return;
+        }
+        var subpaths = fs.readdirSync(dir),
+            subpath;
+        for (var i = 0; i < subpaths.length; ++i) {
+            if (subpaths[i][0] === ".") {
+                continue;
+            }
+            subpath = path.join(dir, subpaths[i]);
+            stat = fs.statSync(subpath);
+            if (stat.isDirectory()) {
+                this.findDirUuid(subpath);
+            } else if (stat.isFile()) {
+                var metastr = subpath.substr(subpath.length - 5, 5);
+                if (metastr == ".meta") {
+                    var jstr = fs.readFileSync(subpath, "utf-8");
+                    var json = JSON.parse(jstr);
+                    if (uuidUtils.isUuid(json["uuid"])) {
+                        this.updateUuidMap(json);
+                        if (json["subMetas"] && typeof json["subMetas"] == "object") {
+                            for (var bb in json["subMetas"]) {
+                                this.updateUuidMap(json["subMetas"][bb]);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    },
+    updateUuidMap: function (json) {
+        if (uuidUtils.isUuid(json["uuid"]) && !uuidMap[json["uuid"]]) {
+            uuidMap[json["uuid"]] = {
+                uuid: uuidUtils.uuidv4(),
+            };
+            if (uuidUtils.isUuid(json["rawTextureUuid"])) {
+                uuidMap[json["rawTextureUuid"]] = {
+                    uuid: uuidUtils.uuidv4(),
+                };
+            }
+        }
+    },
+    isReplaceFile: function (subpath) {
+        let conf = [".anim", ".prefab", ".fire", ".meta"];
+        for (let i = 0; i < conf.length; i++) {
+            let count = conf[i].length;
+            if (subpath.substr(subpath.length - count, count) == conf[i]) {
+                return true;
+            }
+        }
+        return false;
+    },
+    //递归目录找到所有需要替换uuid的文件
+    replaceDirUuid: function (dir) {
+        var stat = fs.statSync(dir);
+        if (!stat.isDirectory()) {
+            return;
+        }
+        var subpaths = fs.readdirSync(dir),
+            subpath;
+        for (var i = 0; i < subpaths.length; ++i) {
+            if (subpaths[i][0] === ".") {
+                continue;
+            }
+            subpath = path.join(dir, subpaths[i]);
+            stat = fs.statSync(subpath);
+            if (stat.isDirectory()) {
+                this.replaceDirUuid(subpath);
+            } else if (stat.isFile()) {
+                if (this.isReplaceFile(subpath)) {
+                    var jstr = fs.readFileSync(subpath, "utf-8");
+                    var json;
+                    try {
+                        json = JSON.parse(jstr);
+                    } catch (error) {
+                        console.log(subpath);
+                    }
+                    if (json) {
+                        this.replaceFileUuid(json);
+                        fs.writeFileSync(subpath, JSON.stringify(json, null, 2));
+                    }
+                }
+            }
+        }
+    },
+    //递归json对象找到所有需要替换uuid
+    replaceFileUuid: function (json) {
+        if (json && typeof json == "object") {
+            if (json["uuid"] && uuidUtils.isUuid(json["uuid"])) {
+                json["uuid"] = uuidMap[json["uuid"]].uuid;
+            }
+            if (json["rawTextureUuid"] && uuidUtils.isUuid(json["rawTextureUuid"])) {
+                json["rawTextureUuid"] = uuidMap[json["rawTextureUuid"]].uuid;
+            }
+            if (json["textureUuid"] && uuidUtils.isUuid(json["textureUuid"])) {
+                json["textureUuid"] = uuidMap[json["textureUuid"]].uuid;
+            }
+            var uuidStr = json["__uuid__"];
+            if (uuidStr && uuidUtils.isUuid(uuidStr)) {
+                //资源
+                if (Reg_Uuid.test(uuidStr)) {
+                    if (uuidMap[uuidStr]) {
+                        json["__uuid__"] = uuidMap[uuidStr].uuid;
+                    }
+                } else {
+                    var uuidStr = uuidUtils.decompressUuid(uuidStr);
+                    if (uuidMap[uuidStr]) {
+                        json["__uuid__"] = UuidUtils.compressUuid(
+                            uuidMap[uuidStr],
+                            false
+                        );
+                    }
+                }
+            }
+            var typeStr = json["__type__"];
+            if (typeStr && uuidUtils.isUuid(typeStr)) {
+                //自定义脚本
+                if (Reg_Uuid.test(typeStr)) {
+                    if (uuidMap[typeStr]) {
+                        json["__type__"] = uuidMap[typeStr].uuid;
+                    }
+                } else {
+                    //cocos为了减少数据量,做了一次特殊的 base64 编码
+                    var de__type__ = uuidUtils.decompressUuid(typeStr);
+                    if (uuidMap[de__type__]) {
+                        json["__type__"] = uuidUtils.compressUuid(
+                            uuidMap[de__type__].uuid,
+                            false
+                        );
+                    }
+                }
+            }
+            if (Object.prototype.toString.call(json) === "[object Array]") {
+                for (var prebidx = 0; prebidx < json.length; prebidx++) {
+                    if (json[prebidx] && typeof json[prebidx] == "object") {
+                        this.replaceFileUuid(json[prebidx]);
+                    }
+                }
+            } else if (Object.prototype.toString.call(json) === "[object Object]") {
+                for (var prebidx in json) {
+                    if (json[prebidx] && typeof json[prebidx] == "object") {
+                        this.replaceFileUuid(json[prebidx]);
+                    }
+                }
+            }
+        }
+    },
+};
diff --git a/packages/replace-uuid/util/uuidUtils.js b/packages/replace-uuid/util/uuidUtils.js
new file mode 100644
index 0000000..34ed9f0
--- /dev/null
+++ b/packages/replace-uuid/util/uuidUtils.js
@@ -0,0 +1,106 @@
+/**
+ * 2.0之后才有Editor.Utils.UuidUtils.compressUuid | decompressUuid的转换 
+ * 这里主要处理base和uuid转换,其他由node-uuid库提供
+ */
+var Uuid = require("node-uuid");
+
+var Base64KeyChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+var AsciiTo64 = new Array(128);
+for (var i = 0; i < 128; ++i) {
+    AsciiTo64[i] = 0;
+}
+for (i = 0; i < 64; ++i) {
+    AsciiTo64[Base64KeyChars.charCodeAt(i)] = i;
+}
+
+var Reg_Dash = /-/g;
+var Reg_Uuid = /^[0-9a-fA-F-]{36}$/;
+var Reg_NormalizedUuid = /^[0-9a-fA-F]{32}$/;
+var Reg_CompressedUuid = /^[0-9a-zA-Z+/]{22,23}$/;
+
+var UuidUtils = {
+    compressUuid: function (uuid, min) {
+        if (Reg_Uuid.test(uuid)) {
+            uuid = uuid.replace(Reg_Dash, "");
+        } else if (!Reg_NormalizedUuid.test(uuid)) {
+            return uuid;
+        }
+        var reserved = min === true ? 2 : 5;
+        return UuidUtils.compressHex(uuid, reserved);
+    },
+    compressHex: function (hexString, reservedHeadLength) {
+        var length = hexString.length;
+        var i;
+        if (typeof reservedHeadLength !== "undefined") {
+            i = reservedHeadLength;
+        } else {
+            i = length % 3;
+        }
+        var head = hexString.slice(0, i);
+        var base64Chars = [];
+        while (i < length) {
+            var hexVal1 = parseInt(hexString[i], 16);
+            var hexVal2 = parseInt(hexString[i + 1], 16);
+            var hexVal3 = parseInt(hexString[i + 2], 16);
+            base64Chars.push(Base64KeyChars[(hexVal1 << 2) | (hexVal2 >> 2)]);
+            base64Chars.push(Base64KeyChars[((hexVal2 & 3) << 4) | hexVal3]);
+            i += 3;
+        }
+        return head + base64Chars.join("");
+    },
+    decompressUuid: function (str) {
+        if (str.length === 23) {
+            // decode base64
+            var hexChars = [];
+            for (var i = 5; i < 23; i += 2) {
+                var lhs = AsciiTo64[str.charCodeAt(i)];
+                var rhs = AsciiTo64[str.charCodeAt(i + 1)];
+                hexChars.push((lhs >> 2).toString(16));
+                hexChars.push((((lhs & 3) << 2) | (rhs >> 4)).toString(16));
+                hexChars.push((rhs & 0xf).toString(16));
+            }
+            //
+            str = str.slice(0, 5) + hexChars.join("");
+        } else if (str.length === 22) {
+            // decode base64
+            var hexChars = [];
+            for (var i = 2; i < 22; i += 2) {
+                var lhs = AsciiTo64[str.charCodeAt(i)];
+                var rhs = AsciiTo64[str.charCodeAt(i + 1)];
+                hexChars.push((lhs >> 2).toString(16));
+                hexChars.push((((lhs & 3) << 2) | (rhs >> 4)).toString(16));
+                hexChars.push((rhs & 0xf).toString(16));
+            }
+            //
+            str = str.slice(0, 2) + hexChars.join("");
+        }
+        return [
+            str.slice(0, 8),
+            str.slice(8, 12),
+            str.slice(12, 16),
+            str.slice(16, 20),
+            str.slice(20),
+        ].join("-");
+    },
+    isUuid: function (str) {
+        if (typeof str == "string") {
+            return (
+                Reg_CompressedUuid.test(str) ||
+                Reg_NormalizedUuid.test(str) ||
+                Reg_Uuid.test(str)
+            );
+        } else {
+            return false;
+        }
+    },
+    uuid: function () {
+        var uuid = Uuid.v4();
+        return UuidUtils.compressUuid(uuid, true);
+    },
+    uuidv4: function () {
+        var uuid = Uuid.v4();
+        return uuid;
+    },
+};
+
+module.exports = UuidUtils;
-- 
2.21.0