完成节点数据的收集

This commit is contained in:
xuyanfeng 2021-04-05 18:38:44 +08:00
parent e0c1f2336c
commit 36a81db153
12 changed files with 263 additions and 354 deletions

View File

@ -1,27 +1,7 @@
# Vue.js Chrome Extension Template ([wcer](https://github.com/YuraDev/wcer)) #说明
> Template for quick creation of Chrome extension on Vuejs c hot reloading when developing.
![Vue.js Chrome Extension Template images](/docs/images/mini.jpg) inject在development模式下无法正常使用暂时的解决办法注释掉`vue-cli-plugin-browser-extension`代码中的
## Installation:
This boilerplate was built as a template for [vue-cli](https://github.com/vuejs/vue-cli) and includes options to customize your final scaffolded app.
``` bash
# install vue-cli
$ npm install -g vue-cli
# create a new project using the template
$ vue init YuraDev/vue-chrome-extension-template my-project
# install dependencies and go!
$ cd my-project
$ npm install # or yarn
$ npm run dev # or yarn dev
``` ```
webpackConfig.plugin('extension-reloader').use(ExtensionReloader, [{ entries, ...extensionReloaderOptions }])
## Structure ```
* [backend](https://developer.chrome.com/extensions/background_pages): Background work of your scripts 详细原因参考:[issues](https://github.com/adambullmer/vue-cli-plugin-browser-extension/issues/120)
* [content](https://developer.chrome.com/extensions/content_scripts) Run in the context of web pages
* [devtools](https://developer.chrome.com/extensions/devtools) - It can add new UI panels and sidebars, interact with the inspected page, get information about network requests, and more.
* [options](https://developer.chrome.com/extensions/options) - To allow users to customize the behavior of your extension, you may wish to provide an options page.
* popup - The page (window) that will be displayed when the icon is clicked
* tab - Your application will work in a separate tab
* ext - Shared scripts
* [manifest.js](https://developer.chrome.com/extensions/manifest) - Descriptions of the application, its rights and possibilities

View File

@ -1,5 +1,8 @@
module.exports = { module.exports = {
root: true, root: true,
globals: {
chrome: true,
},
env: { env: {
node: true, node: true,
webextensions: true, webextensions: true,
@ -37,5 +40,7 @@ module.exports = {
"@typescript-eslint/ban-types": "off", "@typescript-eslint/ban-types": "off",
"@typescript-eslint/no-empty-function": "off", "@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-explicit-any": "off",
"no-prototype-builtins": "off",
"@typescript-eslint/ban-ts-comment": "off",
} }
}; };

View File

@ -5,36 +5,22 @@ let DevtoolsPanel: chrome.runtime.Port | null = null;
let Content: chrome.runtime.Port | null = null; let Content: chrome.runtime.Port | null = null;
console.log('on background') console.log('on background')
function shortConnectionLink(request: any, sender: any, sendResponse: any) { chrome.runtime.onConnect.addListener((port: chrome.runtime.Port) => {
// console.log(`%c[短连接|id:${sender.id}|url:${sender.url}]\n${JSON.stringify(request)}`, 'background:#aaa;color:#BD4E19') console.log(`%c[Connect] ${port.name}`, "color:blue;");
sendResponse && sendResponse(request); port.onMessage.addListener((data: any, sender: any) => {
if (request.msg === PluginMsg.Msg.Support || console.log(`%c[Connect-Message] ${sender.name}\n${JSON.stringify(data)}`, "color:green;")
request.msg === PluginMsg.Msg.ListInfo || sender.postMessage(data);
request.msg === PluginMsg.Msg.NodeInfo) { if (data.msg === PluginMsg.Msg.UrlChange) {
// 将消息转发到devtools if (sender.name === PluginMsg.Page.DevToolsPanel) {
Devtools && Devtools.postMessage(request); Content && Content.postMessage({msg: PluginMsg.Msg.UrlChange, data: {}})
} }
}
function longConnectionLink(data: any, sender: any) {
console.log(`%c[长连接:${sender.name}]\n${JSON.stringify(data)}`, "background:#aaa;color:#bada55")
sender.postMessage(data);
if (data.msg === PluginMsg.Msg.UrlChange) {
if (sender.name === PluginMsg.Page.DevToolsPanel) {
Content && Content.postMessage({msg: PluginMsg.Msg.UrlChange, data: {}})
} }
} // chrome.tabs.executeScript(message.tabId, {code: message.content});
// chrome.tabs.executeScript(message.tabId, {code: message.content}); // port.postMessage(message);
// port.postMessage(message); });
} port.onDisconnect.addListener(function (port: chrome.runtime.Port) {
console.log(`%c[Connect-Dis] ${port.name}`, "color:red");
// 长连接 // port.onMessage.removeListener(longConnectionLink);
chrome.runtime.onConnect.addListener((port) => {
console.log(`%c[长连接:${port.name}] 建立链接!`, "background:#aaa;color:#ff0000");
port.onMessage.addListener(longConnectionLink);
port.onDisconnect.addListener(function (port) {
console.log(`%c[长连接:${port.name}] 断开链接!`, "background:#aaa;color:#00ff00");
port.onMessage.removeListener(longConnectionLink);
if (port.name === PluginMsg.Page.Devtools) { if (port.name === PluginMsg.Page.Devtools) {
Devtools = null; Devtools = null;
} else if (port.name === PluginMsg.Page.Content) { } else if (port.name === PluginMsg.Page.Content) {
@ -55,8 +41,18 @@ chrome.runtime.onConnect.addListener((port) => {
}); });
// background.js 更像是一个主进程,负责整个插件的调度,生命周期和chrome保持一致 // background.js 更像是一个主进程,负责整个插件的调度,生命周期和chrome保持一致
// [短连接] 监听来自content.js发来的事件 // 监听来自content.js发来的事件
chrome.runtime.onMessage.addListener(shortConnectionLink); chrome.runtime.onMessage.addListener((request: any, sender: any, sendResponse: any) => {
console.log(`%c[Message]url:${sender.url}]\n${JSON.stringify(request)}`, 'color:green')
sendResponse && sendResponse(request);
if (request.msg === PluginMsg.Msg.Support ||
request.msg === PluginMsg.Msg.ListInfo ||
request.msg === PluginMsg.Msg.NodeInfo) {
// 将消息转发到devtools
Devtools && Devtools.postMessage(request);
}
}
);
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) { chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
if (changeInfo.status === "complete") { if (changeInfo.status === "complete") {
@ -69,7 +65,8 @@ chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
}) })
function createPluginMenus() { function createPluginMenus() {
// 右键菜单 const menus = [];
let parent = chrome.contextMenus.create({id: "parent", title: "CC-Inspector"}); let parent = chrome.contextMenus.create({id: "parent", title: "CC-Inspector"});
chrome.contextMenus.create({ chrome.contextMenus.create({
id: "test", id: "test",

View File

@ -1,37 +1,32 @@
console.log('content code') // content.js 和原始界面共享DOM具有操作dom的能力
// 具有操作dom的能力 // 但是不共享js,要想访问页面js,只能通过注入的方式
// 加载其他脚本
// content.js 和原始界面共享DOM,但是不共享js,要想访问页面js,只能通过注入的方式
import * as PluginMsg from './core/plugin-msg' import * as PluginMsg from './core/plugin-msg'
function injectScriptToPage(url) { function injectScriptToPage(url: string) {
let content = chrome.extension.getURL(url) let content = chrome.extension.getURL(url)
console.log(`[cc-inspector]注入脚本:${content}`); console.log(`[cc-inspector]注入脚本:${content}`);
let script = document.createElement('script') let script = document.createElement('script')
script.setAttribute('type', 'text/javascript') script.setAttribute('type', 'text/javascript')
script.setAttribute('src', content) script.setAttribute('src', content)
script.onload = function () { script.onload = function () {
// 注入脚本执行完后移除掉 document.body.removeChild(script);
this.parentNode.removeChild(this);
} }
document.body.appendChild(script) document.body.appendChild(script)
} }
debugger
injectScriptToPage("js/inject.js"); injectScriptToPage("js/inject.js");
// 和background.js保持长连接通讯 // 和background.js保持长连接通讯
let conn = chrome.runtime.connect({name: PluginMsg.Page.Content}) let conn = chrome.runtime.connect({name: PluginMsg.Page.Content})
// conn.postMessage('test');
conn.onMessage.addListener(function (data) { conn.onMessage.addListener(function (data) {
// 将background.js的消息返回到injection.js // 将background.js的消息返回到injection.js
console.log(`%c[Connect-Message] ${JSON.stringify(data)}`, "color:green;")
window.postMessage(data, "*"); window.postMessage(data, "*");
}) })
// 接受来自inject.js的消息数据,然后中转到background.js // 接受来自inject.js的消息数据,然后中转到background.js
window.addEventListener('message', function (event) { window.addEventListener('message', function (event) {
let data = event.data; let data = event.data;
if (data.data.log) { console.log(`%c[Window-Message] ${JSON.stringify(data)}`, "color:green;");
}
console.log(`%c[content] ${JSON.stringify(data)}`, "color:#BD4E19");
chrome.runtime.sendMessage(data); chrome.runtime.sendMessage(data);
}, false); }, false);

View File

@ -1,10 +1,10 @@
export const Page = { export const Page = {
Inject: "inject.js", Inject: "Inject",
Devtools: "devtools.js", Devtools: "Devtools",
DevToolsPanel: "DevToolsPanel", DevToolsPanel: "DevToolsPanel",
Content: "content.js", Content: "Content",
Popup: "popup.js", Popup: "Popup",
Options: "options.js", Options: "Options",
} }
export const Msg = { export const Msg = {
NodeInfo: "node_info",// 具体的节点信息 NodeInfo: "node_info",// 具体的节点信息

View File

@ -39,9 +39,6 @@ export default class NodeBaseProperty extends Vue {
@Prop({default: "label"}) @Prop({default: "label"})
private label?: string | undefined private label?: string | undefined
@Prop()
private itemData: any;
setup() { setup() {
} }

View File

@ -55,6 +55,7 @@ import {DataType} from '../data'
@Component({ @Component({
components: {} components: {}
}) })
// todo array
export default class UiProp extends Vue { export default class UiProp extends Vue {
@Prop({default: ""}) @Prop({default: ""})
name: string | undefined; name: string | undefined;

View File

@ -11,6 +11,7 @@ export enum DataType {
class Info { class Info {
public type: DataType = DataType.Number; public type: DataType = DataType.Number;
public data: any;
} }
export class TextData extends Info { export class TextData extends Info {
@ -20,10 +21,19 @@ export class TextData extends Info {
} }
} }
export class ColorData extends Info {
constructor(color: string) {
super();
this.type = DataType.Color;
this.data = color;
}
}
export class StringData extends Info { export class StringData extends Info {
constructor() { constructor(data: string) {
super(); super();
this.type = DataType.String; this.type = DataType.String;
this.data = data;
} }
} }
@ -31,33 +41,44 @@ export class NumberData extends Info {
constructor() { constructor() {
super(); super();
this.type = DataType.Number; this.type = DataType.Number;
this.data = 1;
} }
}
export class BoolData extends Info {
constructor(bol: boolean) {
super();
this.type = DataType.Bool;
this.data = bol;
}
} }
export class Vec2Data extends Info { export class Vec2Data extends Info {
public v1: number = 0; constructor() {
public v2: number = 0;
constructor(v1: number, v2: number) {
super(); super();
this.type = DataType.Vec2 this.type = DataType.Vec2
this.v1 = v1; this.data = [];
this.v2 = v2; return this;
}
add(info: Property) {
this.data.push(info);
return this;
} }
} }
export class Vec3Data extends Info { export class Vec3Data extends Info {
public v1: number = 0;
public v2: number = 0;
public v3: number = 0;
constructor(v1: number, v2: number, v3: number) { constructor() {
super(); super();
this.type = DataType.Vec3 this.type = DataType.Vec3;
this.v1 = v1; this.data = [];
this.v2 = v2; return this;
this.v3 = v3; }
add(info: Property) {
this.data.push(info);
return this;
} }
} }
@ -69,6 +90,29 @@ export class EnumData extends Info {
} }
export class Property {
public name: string = 'property';
public value: Info = new Info();
constructor(name: string, info: Info) {
this.name = name;
this.value = info;
}
}
export class Group {
public name: string = 'group';
public data: Array<Property> = [];
constructor(name: string) {
this.name = name;
}
addProperty(property: Property) {
this.data.push(property)
}
}
class NodeInfo { class NodeInfo {
public type: string = ''; // 类型 public type: string = ''; // 类型

View File

@ -2,8 +2,6 @@
<div id="devtools"> <div id="devtools">
<div v-show="isShowDebug" class="find"> <div v-show="isShowDebug" class="find">
<div v-if="false"> <div v-if="false">
<el-button type="success" @click="onBtnClickTest1">Test1</el-button>
<el-button type="success" @click="onBtnClickTest2">Test2</el-button>
<el-button type="success" @click="onMemoryTest">内存测试</el-button> <el-button type="success" @click="onMemoryTest">内存测试</el-button>
</div> </div>
<div v-if="false"> <div v-if="false">
@ -28,7 +26,7 @@
</div> </div>
</div> </div>
<div class="right"> <div class="right">
<NodeBaseProperty :item-data="treeItemData"></NodeBaseProperty> <NodeBaseProperty :all-group="treeItemData"></NodeBaseProperty>
</div> </div>
</div> </div>
<div v-show="!isShowDebug" class="no-find"> <div v-show="!isShowDebug" class="no-find">
@ -56,7 +54,7 @@ const PluginMsg = require("../core/plugin-msg");
}) })
export default class Index extends Vue { export default class Index extends Vue {
private isShowDebug: boolean = false; private isShowDebug: boolean = false;
treeItemData: Record<string, any> = {}; treeItemData: Array<Record<string, any>> = [];
treeData: Array<Record<string, any>> = [] treeData: Array<Record<string, any>> = []
bgConn: chrome.runtime.Port | null = null// background.js bgConn: chrome.runtime.Port | null = null// background.js
@ -97,11 +95,17 @@ export default class Index extends Vue {
let eventMsg = data.msg; let eventMsg = data.msg;
if (eventMsg === PluginMsg.Msg.ListInfo) { if (eventMsg === PluginMsg.Msg.ListInfo) {
this.isShowDebug = true; this.isShowDebug = true;
this._updateTreeView(eventData); if (!Array.isArray(eventData)) {
eventData = [eventData]
}
this.treeData = eventData;
} else if (eventMsg === PluginMsg.Msg.Support) { } else if (eventMsg === PluginMsg.Msg.Support) {
this.isShowDebug = eventData.support; this.isShowDebug = eventData.support;
} else if (eventMsg === PluginMsg.Msg.NodeInfo) { } else if (eventMsg === PluginMsg.Msg.NodeInfo) {
this.isShowDebug = true; this.isShowDebug = true;
if (!Array.isArray(eventData)) {
eventData = [eventData]
}
this.treeItemData = eventData; this.treeItemData = eventData;
} else if (eventMsg === PluginMsg.Msg.MemoryInfo) { } else if (eventMsg === PluginMsg.Msg.MemoryInfo) {
this.memory = eventData; this.memory = eventData;
@ -114,27 +118,6 @@ export default class Index extends Vue {
for (let i = 0; i < 40; i++) { for (let i = 0; i < 40; i++) {
this.treeData.push({name: `node${i}`, children: [{name: `children11111111111111111111111111111111111111${i}`}]}) this.treeData.push({name: `node${i}`, children: [{name: `children11111111111111111111111111111111111111${i}`}]})
} }
this.treeItemData = {
"uuid": "11",
"name": "name",
"type": "cc_Node",
"height": 1080.986301369863,
"color": "#fff85f",
"opacity": 255,
"components": [
{
"uuid": "Comp.931",
"type": "cc_Canvas",
"name": "Canvas<Canvas>"
},
{
"uuid": "Comp.932",
"type": "HotUpdateScene",
"name": "Canvas<HotUpdateScene>"
}],
"active": true
};
} }
handleNodeClick(data: any) { handleNodeClick(data: any) {
@ -157,191 +140,44 @@ export default class Index extends Vue {
} }
_updateTreeView(data: any) { evalInspectorFunction(func: string, para?: string = '') {
this.treeData = [data.scene]; if (!func || func.length < 0) {
return; console.log("缺失执行函数名!");
// return;
if (this.treeData.length === 0) {//
} else {
} }
if (!chrome || !chrome.devtools) {
let treeData = []; console.log("环境异常,无法执行函数");
debugger return;
let sceneData = data.scene;
if (sceneData) {
// scene info
let dataRoot = {
type: sceneData.type, uuid: sceneData.uuid,
label: sceneData.name, children: []
};
treeData.push(dataRoot);
this.handleNodeClick(dataRoot);
// scene children info
for (let k in sceneData.children) {
let itemSceneData = sceneData.children[k];
// let sceneItem = {uuid: itemSceneData.uuid, label: itemSceneData.name, children: []};
let sceneItem = {};
dealChildrenNode(itemSceneData, sceneItem);
treeData[0].children.push(sceneItem);
}
} }
this.treeData = treeData;
function dealChildrenNode(rootData: any, obj: any) { let injectCode =
obj["data"] = rootData; `if(window.ccinspector){
obj["uuid"] = rootData.uuid; let func = window.ccinspector.${func};
obj["label"] = rootData.name;
obj["type"] = rootData.type;
obj["children"] = [];
let rootChildren = rootData.children;
for (let k in rootChildren) {
let itemData = rootChildren[k];
let item = {};
dealChildrenNode(itemData, item);
obj.children.push(item);
}
}
}
_getInjectScriptString() {
let injectScript = "";
let code = injectScript.toString();
let array = code.split("\n");
array.splice(0, 1);//
array.splice(-1, 1);//
let evalCode = "";
for (let i = 0; i < array.length; i++) {
evalCode += array[i] + "\n";
}
// console.log(evalCode);
return evalCode;
}
evalInspectorFunction(funcString: string, parm?: any) {
if (funcString || funcString.length > 0) {
let injectCode =
`if(window.ccinspector){
let func = window.ccinspector.${funcString};
if(func){ if(func){
console.log("执行${funcString}成功"); console.log("执行${func}成功");
func.apply(window.ccinspector,[${parm}]); func.apply(window.ccinspector,[${para}]);
}else{ }else{
console.log("未发现${funcString}函数"); console.log("未发现${func}函数");
} }
}else{ }else{
console.log("可能脚本没有注入"); console.log("脚本inject.js未注入");
}`; }`;
console.log(injectCode); chrome.devtools.inspectedWindow.eval(injectCode, (result, isException) => {
if (chrome && chrome.devtools) { if (isException) {
let ret = chrome.devtools.inspectedWindow.eval(injectCode, function (result, info) { console.error(isException);
if (info && info.isException) { } else {
console.log(info.value); console.log(`执行结果:${result}`)
}
});
console.log(`ret:${ret}`);
} }
} else { });
console.log("执行失败!");
}
} }
onBtnClickUpdateTree() { onBtnClickUpdateTree() {
this.evalInspectorFunction("updateTreeInfo"); this.evalInspectorFunction("updateTreeInfo");
} }
onBtnClickUpdatePage() { onBtnClickUpdatePage() {
this.evalInspectorFunction("checkIsGamePage", "true"); this.evalInspectorFunction("checkIsGamePage", "true");
// let code = this._getInjectScriptString();
// chrome.devtools.inspectedWindow.eval(code, function () {
// console.log("!");
// });
}
onBtnClickTest1() {
chrome.devtools.inspectedWindow.eval(`window.ccinspector.testMsg1()`);
}
_getTime() {
return new Date().getTime().toString();
}
onBtnClickTest2() {
// chrome.devtools.inspectedWindow.eval(`window.ccinspector.testMsg2()`)
let newData = [
{
name: this._getTime(),
children: [
{
name: this._getTime(),
children: [
{
name: this._getTime(),
}
]
},
{
name: this._getTime(),
}
]
}
];
// this.treeData = newData;
this._update37(this.treeData[0], newData[0]);
}
_update37(oldTreeNode: any, newTreeNode: any) {
debugger
if (!newTreeNode) {
return;
}
if (!oldTreeNode) {
oldTreeNode = {name: "", children: []};
}
if (oldTreeNode.name !== newTreeNode.name) {
oldTreeNode.name = newTreeNode.name;
}
let oldChildren = oldTreeNode.children;
let newChildren = newTreeNode.children;
if (oldChildren.length === 0) {
oldChildren = newChildren;
} else {
// 2: treeData, newTreeData
//
for (let i = 0; i < newChildren.length; i++) {
let itemNew = newChildren[i];
let itemOld = oldChildren[i];
if (itemOld === undefined) {
//
oldChildren.push(itemNew);
} else if (itemNew.name !== itemOld.name) {
//
oldChildren.splice(i, 1, itemNew);
} else {
this._update37(itemOld, itemNew);
}
}
//
if (oldChildren.length > newChildren.length) {
oldChildren.splice(newChildren.length, oldChildren.length - newChildren.length);
}
}
}
onBtnClickTest3() {
// chrome.devtools.inspectedWindow.eval(`window.ccinspector.testMsg3()`)
} }
onMemoryTest() { onMemoryTest() {

View File

@ -11,8 +11,8 @@ if (chrome && chrome.devtools) {
chrome.devtools.panels.create("Cocos", "icons/48.png", Manifest.devtools_page, (panel: chrome.devtools.panels.ExtensionPanel) => { chrome.devtools.panels.create("Cocos", "icons/48.png", Manifest.devtools_page, (panel: chrome.devtools.panels.ExtensionPanel) => {
console.log("[CC-Inspector] Dev Panel Created!"); console.log("[CC-Inspector] Dev Panel Created!");
let conn = chrome.runtime.connect({name: PluginMsg.Page.DevToolsPanel}); let conn = chrome.runtime.connect({name: PluginMsg.Page.DevToolsPanel});
conn.onMessage.addListener(function (event, sender) { conn.onMessage.addListener((event, sender) => {
// debugger console.log(`[Message] ${JSON.stringify(event)}`);
}); });
panel.onShown.addListener((window) => { panel.onShown.addListener((window) => {
@ -27,7 +27,5 @@ if (chrome && chrome.devtools) {
}); });
} }
); );
} }

View File

@ -1,5 +1,6 @@
// eval 注入脚本的代码,变量尽量使用var,后来发现在import之后,let会自动变为var // eval 注入脚本的代码,变量尽量使用var,后来发现在import之后,let会自动变为var
const PluginMsg = require("./core/plugin-msg"); const PluginMsg = require("./core/plugin-msg");
import {BoolData, ColorData, Group, NumberData, Property, StringData, Vec2Data, Vec3Data} from "./devtools/data";
let cc_inspector = { let cc_inspector = {
inspectorGameMemoryStorage: {}, inspectorGameMemoryStorage: {},
@ -22,19 +23,18 @@ let cc_inspector = {
// } // }
}.bind(this), 1000); }.bind(this), 1000);
// 注册cc_after_render事件 // 注册cc_after_render事件
window.addEventListener('message', function (event) { window.addEventListener("message", function (event) {
if (event.data.msg === PluginMsg.Msg.UrlChange) { if (event.data.msg === PluginMsg.Msg.UrlChange) {
this.checkIsGamePage(true); let isCocosGame = this.checkIsGamePage();
} }
}.bind(this)); }.bind(this));
}, },
updateTreeInfo() { updateTreeInfo() {
let isCocosCreatorGame = this.checkIsGamePage(true); let isCocosCreatorGame = this.checkIsGamePage();
if (isCocosCreatorGame) { if (isCocosCreatorGame) {
let scene = cc.director.getScene(); let scene = cc.director.getScene();
if (scene) { if (scene) {
this.postData.scene = { let sendData = {
type: 1,// 标识类型
uuid: scene.uuid, uuid: scene.uuid,
name: scene.name, name: scene.name,
children: [], children: [],
@ -43,40 +43,25 @@ let cc_inspector = {
let sceneChildren = scene.getChildren(); let sceneChildren = scene.getChildren();
for (let i = 0; i < sceneChildren.length; i++) { for (let i = 0; i < sceneChildren.length; i++) {
let node = sceneChildren[i]; let node = sceneChildren[i];
this.getNodeChildren(node, this.postData.scene.children); this.getNodeChildren(node, sendData.children);
} }
// console.log(postData); // console.log(postData);
this.sendMsgToDevTools(PluginMsg.Msg.ListInfo, this.postData); this.sendMsgToDevTools(PluginMsg.Msg.ListInfo, sendData);
} else { } else {
this.postData.scene = null;
this.sendMsgToDevTools(PluginMsg.Msg.Support, {support: false, msg: "未发现游戏场景,不支持调试游戏!"}); this.sendMsgToDevTools(PluginMsg.Msg.Support, {support: false, msg: "未发现游戏场景,不支持调试游戏!"});
} }
} }
}, },
checkIsGamePage(isLog) { // 检测是否包含cc变量
// 检测是否包含cc变量 checkIsGamePage() {
let isCocosCreatorGame = true; let isCocosGame = typeof cc !== "undefined";
let msg = "支持调试游戏!"; this.sendMsgToDevTools(PluginMsg.Msg.Support, {support: isCocosGame});
try { return isCocosGame;
cc
} catch (e) {
isCocosCreatorGame = false;
msg = "不支持调试游戏!";
}
this.sendMsgToDevTools(PluginMsg.Msg.Support, {support: isCocosCreatorGame, msg: msg, log: isLog});
return isCocosCreatorGame;
},
testEval() {
console.log("hello devtools eval")
}, },
testMsg2() { testMsg2() {
debugger
chrome.runtime.connect({name: "inject"}); chrome.runtime.connect({name: "inject"});
}, },
testMsg3() {
debugger
chrome.runtime.sendMessage("ffff");
},
// 收集组件信息 // 收集组件信息
getNodeComponentsInfo(node) { getNodeComponentsInfo(node) {
let ret = []; let ret = [];
@ -130,42 +115,118 @@ let cc_inspector = {
} }
} }
}, },
_getNodeKeys(node) {
let keys = [];
let excludeProperty = ["children", "quat"];
for (let key in node) {
if (!key.startsWith("_") &&
!excludeProperty.includes(key) &&
typeof node[key] !== "function") {
keys.push(key);
}
}
return keys;
},
_getPairProperty(key) {
let pairProperty = {
rotation: ["rotationX", "rotationY"],
anchor: ["anchorX", "anchorY"],
size: ["width", "height"],
position: ["x", "y", "z"],
scale: ["scaleX", "scaleY", "scaleZ"],
};
for (let value in pairProperty) {
let pair = pairProperty[value];
if (pair.includes(key)) {
return {key: value, values: pair};
}
}
return null;
},
_genInfoData(propertyValue) {
let info = null;
switch (typeof propertyValue) {
case "boolean":
info = new BoolData(propertyValue);
break;
case "number":
info = new NumberData(propertyValue);
break;
case "string":
info = new StringData(propertyValue);
break;
default:
if (Array.isArray(propertyValue)) {
} else if (propertyValue instanceof cc.Color) {
let hex = propertyValue.toHEX();
info = new ColorData(`#${hex}`);
} else {
}
break;
}
if (!info) {
console.error(`暂不支持的属性值`, propertyValue);
}
return info;
},
// 获取节点信息 // 获取节点信息
getNodeInfo(uuid) { getNodeInfo(uuid) {
debugger
let node = this.inspectorGameMemoryStorage[uuid]; let node = this.inspectorGameMemoryStorage[uuid];
if (node) { if (node) {
let nodeGroup = new Group("Node");
let keys = this._getNodeKeys(node);
for (let i = 0; i < keys.length; i++) {
let key = keys[i];
let propertyValue = node[key];
let pair = this._getPairProperty(key);
if (pair) {
// 把这个成对的属性剔除掉
pair.values.forEach(item => {
let index = keys.findIndex(el => el === item);
if (index !== -1) {
keys.splice(index, 1);
}
});
// 序列化成对的属性
let info = null;
let pairValues = pair.values;
if (pairValues.length === 2) {
info = new Vec2Data();
} else if (pairValues.length === 3) {
info = new Vec3Data();
}
pairValues.forEach(el => {
if (el in node) {
let vecData = this._genInfoData(node[el]);
if (vecData) {
info.add(new Property(el, vecData));
}
} else {
console.warn(`属性异常,节点丢失属性: ${el},请检查 pairProperty的设置`);
}
});
if (info) {
let property = new Property(pair.key, info);
nodeGroup.addProperty(property);
}
} else {
let info = this._genInfoData(propertyValue);
if (info) {
nodeGroup.addProperty(new Property(key, info));
}
}
}
let nodeComp = this.getNodeComponentsInfo(node); let nodeComp = this.getNodeComponentsInfo(node);
let nodeData = { let nodeData = {
type: node.constructor.name, type: node.constructor.name,
uuid: node.uuid,
name: node.name,
x: node.x,
y: node.y,
zIndex: node.zIndex,
childrenCount: node.childrenCount,
children: [],
width: node.width,
height: node.height,
color: node.color.toCSS(),
opacity: node.opacity,
rotation: node.rotation,
rotationX: node.rotationX,
rotationY: node.rotationY,
anchorX: node.anchorX,
anchorY: node.anchorY,
scaleX: node.scaleX,
scaleY: node.scaleY,
skewX: node.skewX,
skewY: node.skewY,
components: nodeComp components: nodeComp
}; };
let nodeType = node.constructor.name; this.sendMsgToDevTools(PluginMsg.Msg.NodeInfo, nodeGroup);
if (nodeType === 'cc_Scene') {
} else {
nodeData.active = node.active;
}
this.sendMsgToDevTools(PluginMsg.Msg.NodeInfo, nodeData);
} else { } else {
// 未获取到节点数据 // 未获取到节点数据
console.log("未获取到节点数据"); console.log("未获取到节点数据");
@ -190,6 +251,7 @@ let cc_inspector = {
data.push(nodeData); data.push(nodeData);
}, },
sendMsgToDevTools(msg, data) { sendMsgToDevTools(msg, data) {
// 发送给content.js处理
window.postMessage({msg: msg, data: data}, "*"); window.postMessage({msg: msg, data: data}, "*");
}, },
@ -207,7 +269,7 @@ let cc_inspector = {
}, },
}); });
} }
} };
window.ccinspector = window.ccinspector || cc_inspector; window.ccinspector = window.ccinspector || cc_inspector;
window.ccinspector.init && window.ccinspector.init();// 执行初始化函数 window.ccinspector.init && window.ccinspector.init();// 执行初始化函数

View File

@ -28,13 +28,7 @@ module.exports = {
} }
}, },
configureWebpack: { configureWebpack: {
mode: "development", mode: "development",// production
devtool: "#source-map", devtool: "#source-map",
entry: {
inject: Path.join(__dirname, "src/inject.js"),
},
plugins: [
// new Copy([{src: "src/inject.js", dest: "js/inject.js"}]),
]
} }
}; };