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 {
constructor() {
constructor(data: number) {
super();
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 {
text-align: left !important;
}
}
.el-tree {
width: 100%;
}

View File

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

View File

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

View File

@ -53,31 +53,12 @@ export default class properties extends Vue {
}
_initValue() {
debugger
if (this.allGroup) {
this.allGroup.forEach(item => {
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) {
if (chrome && chrome.devtools) {
chrome.devtools.inspectedWindow.eval(code);

View File

@ -7,26 +7,43 @@ if (chrome && chrome.devtools) {
chrome.devtools.panels.elements.createSidebarPane('Cocos', function (sidebar) {
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
chrome.devtools.panels.create("Cocos", "icons/48.png", Manifest.devtools_page, (panel: chrome.devtools.panels.ExtensionPanel) => {
console.log("[CC-Inspector] Dev Panel Created!");
let conn = chrome.runtime.connect({name: PluginMsg.Page.DevToolsPanel});
conn.onDisconnect.addListener(() => {
if (!connect) {
return;
}
connect.onDisconnect.addListener(() => {
console.log(`%c[Connect-Dis]`, 'color:red;')
})
conn.onMessage.addListener((event, sender) => {
connect.onMessage.addListener((event, sender) => {
console.log(`[Message] ${JSON.stringify(event)}`);
});
panel.onShown.addListener((window) => {
// 面板显示查询是否是cocos游戏
console.log("panel show");
conn.postMessage({msg: PluginMsg.Msg.UrlChange, data: {}})
if (connect) {
connect.postMessage({msg: PluginMsg.Msg.UrlChange, data: {}})
}
});
panel.onHidden.addListener(() => {
// 面板隐藏
console.log("panel hide");
});
panel.onSearch.addListener(function (action, query) {
// ctrl+f 查找触发
if (connect) {
console.log("panel search!");
}
});
}
);

View File

@ -3,3 +3,29 @@ export class NodeData {
name: string = '';
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 {Component, Prop} from "vue-property-decorator"
import {DataType} from '../data'
import {DataType} from './data'
@Component({
components: {}

View File

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

View File

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