This commit is contained in:
xuyanfeng 2021-04-22 19:09:35 +08:00
parent 993d918aca
commit 0e04f8b708
11 changed files with 258 additions and 147 deletions

View File

@ -64,10 +64,10 @@ export class StringData extends Info {
} }
export class NumberData extends Info { export class NumberData extends Info {
constructor() { constructor(data: number) {
super(); super();
this.type = DataType.Number; this.type = DataType.Number;
this.data = 1; this.data = data;
} }
} }

View File

@ -0,0 +1,18 @@
interface ICCInspector extends Object {
devPageCallEntry(para: string): void;
init(): void;
}
declare interface Window {
CCInspector: ICCInspector;
CCInspectorPara: string;
}
debugger
if (window.hasOwnProperty('CCInspector')) {
if (window.CCInspector.hasOwnProperty('devPageCallEntry')) {
window.CCInspector.devPageCallEntry(window.CCInspectorPara);
} else {
console.log("脚本inject.js未注入")
}
}

View File

@ -11,8 +11,13 @@
} }
} }
} }
.el-input{
input{ .el-input {
input {
text-align: left !important; text-align: left !important;
} }
} }
.el-tree {
width: 100%;
}

View File

@ -43,10 +43,9 @@
<script lang="ts"> <script lang="ts">
import Vue from "vue"; import Vue from "vue";
import {Component, Prop} from "vue-property-decorator"; import {Component} from "vue-property-decorator";
import properties from "./propertys.vue"; import properties from "./propertys.vue";
import {DataType, testData} from "./data" import {DataSupport, ExecutePara, ExecuteParaType, NodeData} from "@/devtools/type";
import {NodeData} from "@/devtools/type";
const PluginMsg = require("../core/plugin-msg"); const PluginMsg = require("../core/plugin-msg");
@Component({ @Component({
@ -76,7 +75,6 @@ export default class Index extends Vue {
timerID: number = 0; timerID: number = 0;
created() { created() {
this.onTestData();
if (chrome && chrome.runtime) { if (chrome && chrome.runtime) {
this._initChromeRuntimeConnect(); this._initChromeRuntimeConnect();
} }
@ -87,6 +85,47 @@ export default class Index extends Vue {
}, false); }, false);
} }
_onMsgListInfo(eventData: Array<NodeData>) {
this.isShowDebug = true;
if (!Array.isArray(eventData)) {
eventData = [eventData]
}
this.treeData = eventData;
if (this.selectedUUID) {
this.$nextTick(() => {
//@ts-ignore
this.$refs.tree.setCurrentKey(this.selectedUUID);
// todo node
})
}
}
_onMsgNodeInfo(eventData: any) {
this.isShowDebug = true;
if (!Array.isArray(eventData)) {
eventData = [eventData]
}
this.treeItemData = eventData;
}
_onMsgMemory(eventData: any) {
this.memory = eventData;
}
_onMsgSupport(data: DataSupport) {
this.isShowDebug = data.support;
if (data.support) {
this.onBtnClickUpdateTree();
} else {
this._reset();
}
}
_reset() {
this.treeData = [];
this.treeItemData = [];
}
_initChromeRuntimeConnect() { _initChromeRuntimeConnect() {
// chrome.devtools.inspectedWindow.tabId // chrome.devtools.inspectedWindow.tabId
// background.js // background.js
@ -95,49 +134,37 @@ export default class Index extends Vue {
if (!data) { if (!data) {
return; return;
} }
let eventData: Array<NodeData> = data.data;
let eventMsg = data.msg; let eventData: any = data.data;
if (eventMsg === PluginMsg.Msg.ListInfo) { console.log(data)
this.isShowDebug = true; switch (data.msg) {
if (!Array.isArray(eventData)) { case PluginMsg.Msg.ListInfo: {
eventData = [eventData] this._onMsgListInfo(eventData as Array<NodeData>);
break;
} }
this.treeData = eventData; case PluginMsg.Msg.Support: {
if (this.selectedUUID) { this._onMsgSupport(eventData as DataSupport)
this.$nextTick(() => { break;
this.$refs.tree.setCurrentKey(this.selectedUUID);
// todo node
})
} }
} else if (eventMsg === PluginMsg.Msg.Support) { case PluginMsg.Msg.NodeInfo: {
this.isShowDebug = eventData.support; this._onMsgNodeInfo(eventData);
} else if (eventMsg === PluginMsg.Msg.NodeInfo) { break;
this.isShowDebug = true; }
if (!Array.isArray(eventData)) { case PluginMsg.Msg.MemoryInfo: {
eventData = [eventData] this._onMsgMemory(eventData)
break;
} }
this.treeItemData = eventData;
} else if (eventMsg === PluginMsg.Msg.MemoryInfo) {
this.memory = eventData;
} }
}); });
} }
onTestData() {
for (let i = 0; i < 40; i++) {
this.treeData.push({name: `node${i}`, children: [{name: `children11111111111111111111111111111111111111${i}`}]})
}
this.treeItemData = testData;
}
handleNodeClick(data: NodeData) { handleNodeClick(data: NodeData) {
this.selectedUUID = data.uuid; this.selectedUUID = data.uuid;
// todo // todo
// console.log(data); // console.log(data);
let uuid = data.uuid; let uuid = data.uuid;
if (uuid !== undefined) { if (uuid !== undefined) {
this.evalInspectorFunction("getNodeInfo", `"${uuid}"`); this.runToContentScript(ExecuteParaType.GetNodeInfo, uuid);
} }
} }
@ -152,29 +179,21 @@ export default class Index extends Vue {
} }
evalInspectorFunction(func: string, para?: string = '') { runToContentScript(type: ExecuteParaType, data?: any) {
if (!func || func.length < 0) {
console.log("缺失执行函数名!");
return;
}
if (!chrome || !chrome.devtools) { if (!chrome || !chrome.devtools) {
console.log("环境异常,无法执行函数"); console.log("环境异常,无法执行函数");
return; return;
} }
let para: ExecutePara = new ExecutePara(type, data);
let injectCode = //@ts-ignore
`if(window.ccinspector){ chrome.tabs.executeScript(null, {code: `var CCInspectorPara='${JSON.stringify(para)}';`}, () => {
let func = window.ccinspector.${func}; //@ts-ignore
if(func){ chrome.tabs.executeScript(null, {file: "js/execute.js"})
console.log("执行${func}成功"); });
func.apply(window.ccinspector,[${para}]);
}else{
console.log("未发现${func}函数");
} }
}else{
console.log("脚本inject.js未注入"); _inspectedCode() {
}`; let injectCode = '';
chrome.devtools.inspectedWindow.eval(injectCode, (result, isException) => { chrome.devtools.inspectedWindow.eval(injectCode, (result, isException) => {
if (isException) { if (isException) {
console.error(isException); console.error(isException);
@ -185,19 +204,19 @@ export default class Index extends Vue {
} }
onBtnClickUpdateTree() { onBtnClickUpdateTree() {
this.evalInspectorFunction("updateTreeInfo"); this.runToContentScript(ExecuteParaType.UpdateTreeInfo);
} }
onBtnClickUpdatePage() { onBtnClickUpdatePage() {
this.evalInspectorFunction("checkIsGamePage", "true"); this.runToContentScript(ExecuteParaType.CheckGamePage, true);
} }
onMemoryTest() { onMemoryTest() {
this.evalInspectorFunction("onMemoryInfo"); this.runToContentScript(ExecuteParaType.MemoryInfo);
} }
onNodeExpand(data: NodeData, a, b) { onNodeExpand(data: NodeData) {
if (data.hasOwnProperty('uuid')) { if (data.hasOwnProperty('uuid') && data.uuid) {
this.expandedKeys.push(data.uuid) this.expandedKeys.push(data.uuid)
} }
} }

View File

@ -1,5 +1,5 @@
// eval 注入脚本的代码,变量尽量使用var,后来发现在import之后,let会自动变为var // eval 注入脚本的代码,变量尽量使用var,后来发现在import之后,let会自动变为var
const PluginMsg = require("./core/plugin-msg"); import * as PluginMsg from '../core/plugin-msg'
import { import {
ArrayData, ArrayData,
BoolData, BoolData,
@ -11,33 +11,59 @@ import {
StringData, StringData,
Vec2Data, Vec2Data,
Vec3Data Vec3Data
} from "./devtools/data"; } from "./data";
import {ExecutePara, ExecuteParaType} from './type'
class CCInspector implements ICCInspector {
inspectorGameMemoryStorage: Record<string, any> = {}
let cc_inspector = {
inspectorGameMemoryStorage: {},
postData: {
scene: {
name: "",
children: []
},
},
init() { init() {
setInterval(function () { setInterval(() => {
// this.checkIsGamePage(true); // this.checkIsGamePage(true);
// if (this.stop) { // if (this.stop) {
// } else { // } else {
// } // }
}.bind(this), 1000); }, 1000);
// 注册cc_after_render事件 // 注册cc_after_render事件
window.addEventListener("message", function (event) { window.addEventListener("message", (event: any) => {
if (event.data.msg === PluginMsg.Msg.UrlChange) { if (event.data.msg === PluginMsg.Msg.UrlChange) {
let isCocosGame = this.checkIsGamePage(); let isCocosGame = this._isCocosGame();
this.sendMsgToDevTools(PluginMsg.Msg.Support, {support: isCocosGame});
} }
}.bind(this)); });
}, }
devPageCallEntry(str: string) {
let para: ExecutePara = JSON.parse(str);
debugger
if (this._isCocosGame()) {
switch (para.type) {
case ExecuteParaType.None:
break;
case ExecuteParaType.UpdateTreeInfo:
this.updateTreeInfo();
break;
case ExecuteParaType.CheckGamePage:
break;
case ExecuteParaType.MemoryInfo:
break;
case ExecuteParaType.SetProperty:
break;
case ExecuteParaType.GetNodeInfo:
this.getNodeInfo(para.data as string);
break;
}
} else {
this.sendMsgToDevTools(PluginMsg.Msg.Support, {support: false});
}
}
updateTreeInfo() { updateTreeInfo() {
let isCocosCreatorGame = this.checkIsGamePage(); let isCocosCreatorGame = this._isCocosGame();
if (isCocosCreatorGame) { if (isCocosCreatorGame) {
//@ts-ignore
let scene = cc.director.getScene(); let scene = cc.director.getScene();
if (scene) { if (scene) {
let sendData = { let sendData = {
@ -56,9 +82,10 @@ let cc_inspector = {
this.sendMsgToDevTools(PluginMsg.Msg.Support, {support: false, msg: "未发现游戏场景,不支持调试游戏!"}); this.sendMsgToDevTools(PluginMsg.Msg.Support, {support: false, msg: "未发现游戏场景,不支持调试游戏!"});
} }
} }
}, }
// 收集节点信息 // 收集节点信息
getNodeChildren(node, data) { getNodeChildren(node: any, data: Array<any>) {
let nodeData = { let nodeData = {
uuid: node.uuid, uuid: node.uuid,
name: node.name, name: node.name,
@ -71,14 +98,14 @@ let cc_inspector = {
this.getNodeChildren(childItem, nodeData.children); this.getNodeChildren(childItem, nodeData.children);
} }
data.push(nodeData); data.push(nodeData);
}, }
// 检测是否包含cc变量
checkIsGamePage() { _isCocosGame() {
let isCocosGame = typeof cc !== "undefined"; // @ts-ignore 检测是否包含cc变量
this.sendMsgToDevTools(PluginMsg.Msg.Support, {support: isCocosGame}); return typeof cc !== "undefined";
return isCocosGame; }
},
pluginSetNodeActive(uuid, isActive) { pluginSetNodeActive(uuid: string, isActive: number) {
let node = this.inspectorGameMemoryStorage[uuid]; let node = this.inspectorGameMemoryStorage[uuid];
if (node) { if (node) {
if (isActive === 1) { if (isActive === 1) {
@ -87,8 +114,9 @@ let cc_inspector = {
node.active = false; node.active = false;
} }
} }
}, }
_getNodeKeys(node) {
_getNodeKeys(node: any) {
let keys = []; let keys = [];
let excludeProperty = [ let excludeProperty = [
"children", "quat", "node", "children", "quat", "node",
@ -104,9 +132,10 @@ let cc_inspector = {
} }
} }
return keys; return keys;
}, }
_getPairProperty(key) {
let pairProperty = { _getPairProperty(key: string) {
let pairProperty: Record<string, any> = {
rotation: ["rotationX", "rotationY"], rotation: ["rotationX", "rotationY"],
anchor: ["anchorX", "anchorY"], anchor: ["anchorX", "anchorY"],
size: ["width", "height"], size: ["width", "height"],
@ -115,14 +144,17 @@ let cc_inspector = {
designResolution: ["width", "height"], // 这个比较特殊在key下边其他的都不是在key下 designResolution: ["width", "height"], // 这个比较特殊在key下边其他的都不是在key下
}; };
for (let value in pairProperty) { for (let value in pairProperty) {
if (pairProperty.hasOwnProperty(value)) {
let pair = pairProperty[value]; let pair = pairProperty[value];
if (pair.includes(key)) { if (pair.includes(key)) {
return {key: value, values: pair}; return {key: value, values: pair};
} }
} }
}
return null; return null;
}, }
_genInfoData(propertyValue, path) {
_genInfoData(propertyValue: any, path: any) {
let info = null; let info = null;
switch (typeof propertyValue) { switch (typeof propertyValue) {
case "boolean": case "boolean":
@ -137,6 +169,7 @@ let cc_inspector = {
default: default:
if (propertyValue == null || typeof propertyValue === "undefined") { if (propertyValue == null || typeof propertyValue === "undefined") {
info = new NullOrUndefinedData(); info = new NullOrUndefinedData();
//@ts-ignore
} else if (propertyValue instanceof cc.Color) { } else if (propertyValue instanceof cc.Color) {
let hex = propertyValue.toHEX(); let hex = propertyValue.toHEX();
info = new ColorData(`#${hex}`); info = new ColorData(`#${hex}`);
@ -155,8 +188,9 @@ let cc_inspector = {
} }
return info; return info;
}, }
_getGroupData(node) {
_getGroupData(node: any) {
let nodeGroup = new Group(node.constructor.name); let nodeGroup = new Group(node.constructor.name);
let keys = this._getNodeKeys(node); let keys = this._getNodeKeys(node);
for (let i = 0; i < keys.length; i++) { for (let i = 0; i < keys.length; i++) {
@ -165,26 +199,26 @@ let cc_inspector = {
let pair = this._getPairProperty(key); let pair = this._getPairProperty(key);
if (pair) { if (pair) {
// 把这个成对的属性剔除掉 // 把这个成对的属性剔除掉
pair.values.forEach(item => { pair.values.forEach((item: string) => {
let index = keys.findIndex(el => el === item); let index = keys.findIndex(el => el === item);
if (index !== -1) { if (index !== -1) {
keys.splice(index, 1); keys.splice(index, 1);
} }
}); });
// 序列化成对的属性 // 序列化成对的属性
let info = null; let info: Vec2Data | Vec3Data | null = null;
let pairValues = pair.values; let pairValues = pair.values;
if (pairValues.length === 2) { if (pairValues.length === 2) {
info = new Vec2Data(); info = new Vec2Data();
} else if (pairValues.length === 3) { } else if (pairValues.length === 3) {
info = new Vec3Data(); info = new Vec3Data();
} }
pairValues.forEach(el => { pairValues.forEach((el: string) => {
if (el in node) { if (el in node) {
let propertyPath = [node.uuid, el]; let propertyPath = [node.uuid, el];
let vecData = this._genInfoData(node[el], propertyPath); let vecData = this._genInfoData(node[el], propertyPath);
if (vecData) { if (vecData) {
info.add(new Property(el, vecData)); info && info.add(new Property(el, vecData));
} }
} else { } else {
console.warn(`属性异常,节点丢失属性: ${el},请检查 pairProperty的设置`); console.warn(`属性异常,节点丢失属性: ${el},请检查 pairProperty的设置`);
@ -203,9 +237,10 @@ let cc_inspector = {
} }
} }
return nodeGroup; return nodeGroup;
}, }
// 获取节点信息 // 获取节点信息
getNodeInfo(uuid) { getNodeInfo(uuid: string) {
let node = this.inspectorGameMemoryStorage[uuid]; let node = this.inspectorGameMemoryStorage[uuid];
if (node) { if (node) {
let groupData = []; let groupData = [];
@ -225,29 +260,35 @@ let cc_inspector = {
// 未获取到节点数据 // 未获取到节点数据
console.log("未获取到节点数据"); console.log("未获取到节点数据");
} }
}, }
logValue(uuid, key) {
logValue(uuid: string, key: string) {
let nodeOrComp = this.inspectorGameMemoryStorage[uuid]; let nodeOrComp = this.inspectorGameMemoryStorage[uuid];
if (nodeOrComp) { if (nodeOrComp) {
console.log(nodeOrComp[key]); console.log(nodeOrComp[key]);
} }
}, }
setValue(uuid, key, value) {
setValue(uuid: string, key: string, value: string) {
let nodeOrComp = this.inspectorGameMemoryStorage[uuid]; let nodeOrComp = this.inspectorGameMemoryStorage[uuid];
if (nodeOrComp && key in nodeOrComp) { if (nodeOrComp && key in nodeOrComp) {
nodeOrComp[key] = value; nodeOrComp[key] = value;
} }
}, }
sendMsgToDevTools(msg, data) {
sendMsgToDevTools(msg: string, data: any) {
// 发送给content.js处理 // 发送给content.js处理
window.postMessage({msg: msg, data: data}, "*"); window.postMessage({msg: msg, data: data}, "*");
}, }
onMemoryInfo() { onMemoryInfo() {
this.sendMsgToDevTools(PluginMsg.Msg.MemoryInfo, { this.sendMsgToDevTools(PluginMsg.Msg.MemoryInfo, {
performance: { performance: {
// @ts-ignore
jsHeapSizeLimit: window.performance.memory.jsHeapSizeLimit, jsHeapSizeLimit: window.performance.memory.jsHeapSizeLimit,
// @ts-ignore
totalJSHeapSize: window.performance.memory.totalJSHeapSize, totalJSHeapSize: window.performance.memory.totalJSHeapSize,
// @ts-ignore
usedJSHeapSize: window.performance.memory.usedJSHeapSize, usedJSHeapSize: window.performance.memory.usedJSHeapSize,
}, },
console: { console: {
@ -257,12 +298,14 @@ let cc_inspector = {
}, },
}); });
} }
}; }
window.addEventListener("message", (a, b, c) => {
console.log(a, b, c); window.addEventListener("message", (a: any) => {
console.log(a);
}); });
window.ccinspector = window.ccinspector || cc_inspector; let inspector = new CCInspector();
window.ccinspector.init && window.ccinspector.init();// 执行初始化函数 inspector.init();
window.CCInspector = inspector;

View File

@ -53,31 +53,12 @@ export default class properties extends Vue {
} }
_initValue() { _initValue() {
debugger
if (this.allGroup) { if (this.allGroup) {
this.allGroup.forEach(item => { this.allGroup.forEach(item => {
this.$set(item, 'fold', false); this.$set(item, 'fold', false);
}) })
} }
} }
changeColor() {
let color = this.itemData.color;
console.log("color:" + color);
this._evalCode(
"window.ccinspector.pluginSetNodeColor('" +
this.itemData.uuid + "','" +
color + "');");
this._freshNode();
}
_freshNode() {
let uuid = this.itemData.uuid;
let code2 = "window.ccinspector.getNodeInfo('" + uuid + "')";
this._evalCode(code2);
}
_evalCode(code: string) { _evalCode(code: string) {
if (chrome && chrome.devtools) { if (chrome && chrome.devtools) {
chrome.devtools.inspectedWindow.eval(code); chrome.devtools.inspectedWindow.eval(code);

View File

@ -7,26 +7,43 @@ if (chrome && chrome.devtools) {
chrome.devtools.panels.elements.createSidebarPane('Cocos', function (sidebar) { chrome.devtools.panels.elements.createSidebarPane('Cocos', function (sidebar) {
sidebar.setObject({some_data: "some data to show!"}); sidebar.setObject({some_data: "some data to show!"});
}); });
// 和background建立连接
let connect: chrome.runtime.Port | null = null;
if (chrome && chrome.runtime) {
connect = chrome.runtime.connect({name: PluginMsg.Page.DevToolsPanel});
}
// 创建devtools-panel // 创建devtools-panel
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}); if (!connect) {
conn.onDisconnect.addListener(() => { return;
}
connect.onDisconnect.addListener(() => {
console.log(`%c[Connect-Dis]`, 'color:red;') console.log(`%c[Connect-Dis]`, 'color:red;')
}) })
conn.onMessage.addListener((event, sender) => { connect.onMessage.addListener((event, sender) => {
console.log(`[Message] ${JSON.stringify(event)}`); console.log(`[Message] ${JSON.stringify(event)}`);
}); });
panel.onShown.addListener((window) => { panel.onShown.addListener((window) => {
// 面板显示查询是否是cocos游戏
console.log("panel show"); console.log("panel show");
conn.postMessage({msg: PluginMsg.Msg.UrlChange, data: {}}) if (connect) {
connect.postMessage({msg: PluginMsg.Msg.UrlChange, data: {}})
}
}); });
panel.onHidden.addListener(() => { panel.onHidden.addListener(() => {
// 面板隐藏
console.log("panel hide"); console.log("panel hide");
}); });
panel.onSearch.addListener(function (action, query) { panel.onSearch.addListener(function (action, query) {
// ctrl+f 查找触发
if (connect) {
console.log("panel search!"); console.log("panel search!");
}
}); });
} }
); );

View File

@ -3,3 +3,29 @@ export class NodeData {
name: string = ''; name: string = '';
children: Array<NodeData> = [] children: Array<NodeData> = []
} }
export class DataSupport {
support: boolean = false;
msg?: string;
}
export enum ExecuteParaType {
None,
UpdateTreeInfo,
CheckGamePage,
MemoryInfo,
SetProperty,
GetNodeInfo,
}
export class ExecutePara {
static Type = ExecuteParaType;
type: ExecuteParaType = ExecuteParaType.None;
data: any;
constructor(type: ExecuteParaType, data?: any) {
this.type = type;
this.data = data;
}
}

View File

@ -56,7 +56,7 @@
import Vue from "vue" import Vue from "vue"
import {Component, Prop} from "vue-property-decorator" import {Component, Prop} from "vue-property-decorator"
import {DataType} from '../data' import {DataType} from './data'
@Component({ @Component({
components: {} components: {}

View File

@ -38,7 +38,8 @@
"<all_urls>" "<all_urls>"
], ],
"js": [ "js": [
"js/content.js" "js/content.js",
"js/execute.js"
], ],
"run_at": "document_end", "run_at": "document_end",
"all_frames": true "all_frames": true

View File

@ -18,7 +18,8 @@ module.exports = {
contentScripts: { contentScripts: {
entries: { entries: {
content: "src/content.ts", content: "src/content.ts",
inject: "src/inject.js" execute: "src/devtools/execute.ts",
inject: "src/devtools/inject.ts",
}, },
}, },
background: { background: {