This commit is contained in:
cheney2013
2023-06-02 12:25:21 +08:00
parent ed535d0481
commit 64abcdadf1
788 changed files with 42717 additions and 0 deletions

View File

@@ -0,0 +1,59 @@
import { methods } from "../../main";
import { updatePropByDump } from "./utils/prop";
//@ts-ignore
import packageJSON from "../../../package.json";
type Selector<$> = { $: Record<keyof $, any | null> };
export const template = `
<div class="component-container">
</div>
<ui-prop>
<ui-button class="staticButton" tooltip="复制到剪贴板,出现异常时方便检查">
查看保存的数据
</ui-button>
</ui-prop>
`;
export const $ = {
componentContainer: ".component-container",
staticButton: ".staticButton"
};
export function ready(this: Selector<typeof $> & typeof methods) {
// // @ts-ignore
// this.elements = {
// // @ts-ignore
// stringText: {
// update: (element: any, dump: any) => {
// console.log("stringText update");
// },
// create(dump: any) {
// const prop = document.createElement("ui-prop");
// // @ts-ignore
// prop.dump = dump;
// const button = document.createElement("ui-button");
// button.innerText = dump.value;
// button.addEventListener("click", () => {
// console.log("clicked stringText property");
// });
// prop.appendChild(button);
// return prop;
// }
// }
// };
this.$.staticButton.addEventListener("click", async () => {
const json = await Editor.Message.request("scene", "execute-scene-script", {
name: packageJSON.name,
method: "copyRecords",
args: [(this.dump as any).value.node.value.uuid]
});
Editor.Panel.open("uistate-inspector", json);
});
}
export function update(this: Selector<typeof $> & typeof methods, dump: any) {
// 缓存 dump 数据,请挂在 this 上,否则多开的时候可能出现问题
this.dump = dump;
updatePropByDump(this, dump);
}

View File

@@ -0,0 +1,445 @@
//@ts-nocheck
/*
* Returns the ordered PropMap
* @param {*} value of dump
* @returns {key:string dump:object}[]
*/
export function sortProp(propMap) {
const orderList = [];
const normalList = [];
Object.keys(propMap).forEach(key => {
const item = propMap[key];
if (item != null) {
if ("displayOrder" in item) {
orderList.push({
key,
dump: item
});
} else {
normalList.push({
key,
dump: item
});
}
}
});
orderList.sort((a, b) => a.dump.displayOrder - b.dump.displayOrder);
return orderList.concat(normalList);
}
/**
*
* This method is used to update the custom node
* @param {HTMLElement} container
* @param {string[]} excludeList
* @param {object} dump
* @param {(element,prop)=>void} update
*/
export function updateCustomPropElements(container, excludeList, dump, update) {
const sortedProp = exports.sortProp(dump.value);
container.$ = container.$ || {};
/**
* @type {Array<HTMLElement>}
*/
const children = [];
sortedProp.forEach(prop => {
if (!excludeList.includes(prop.key)) {
if (!prop.dump.visible) {
return;
}
let node = container.$[prop.key];
if (!node) {
node = document.createElement("ui-prop");
node.setAttribute("type", "dump");
node.dump = prop.dump;
node.key = prop.key;
container.$[prop.key] = node;
}
if (typeof update === "function") {
update(node, prop);
}
children.push(node);
}
});
const currentChildren = Array.from(container.children);
children.forEach((child, i) => {
if (child === currentChildren[i]) {
return;
}
container.appendChild(child);
});
// delete extra children
currentChildren.forEach($child => {
if (!children.includes($child)) {
$child.remove();
}
});
}
/**
* Tool function: recursively set readonly in resource data
*/
export function loopSetAssetDumpDataReadonly(dump) {
if (typeof dump !== "object") {
return;
}
if (dump.readonly === undefined) {
return;
}
dump.readonly = true;
if (dump.isArray) {
for (let i = 0; i < dump.value.length; i++) {
exports.loopSetAssetDumpDataReadonly(dump.value[i]);
}
return;
}
for (const key in dump.value) {
exports.loopSetAssetDumpDataReadonly(dump.value[key]);
}
}
/**
* Tool functions: set to unavailable
* @param {object} data dump | function
* @param element
*/
export function setDisabled(data, element) {
if (!element) {
return;
}
let disabled = data;
if (typeof data === "function") {
disabled = data();
}
if (disabled === true) {
element.setAttribute("disabled", "true");
} else {
element.removeAttribute("disabled");
}
}
/**
* Tool function: Set read-only status
* @param {object} data dump | function
* @param element
*/
export function setReadonly(data, element) {
if (!element) {
return;
}
let readonly = data;
if (typeof data === "function") {
readonly = data();
}
if (readonly === true) {
element.setAttribute("readonly", "true");
} else {
element.removeAttribute("readonly");
}
if (element.render && element.dump) {
element.dump.readonly = readonly;
element.render();
}
}
/**
* Tool function: Set the display status
* @param {Function | boolean} data dump | function
* @param {HTMLElement} element
*/
export function setHidden(data, element) {
if (!element) {
return;
}
let hidden = data;
if (typeof data === "function") {
hidden = data();
}
if (hidden === true) {
element.setAttribute("hidden", "");
} else {
element.removeAttribute("hidden");
}
}
export function updatePropByDump(panel, dump) {
panel.dump = dump;
if (!panel.elements) {
panel.elements = {};
}
if (!panel.$props) {
panel.$props = {};
}
if (!panel.$groups) {
panel.$groups = {};
}
const oldPropKeys = Object.keys(panel.$props);
const newPropKeys = [];
Object.keys(dump.value).forEach((key, index) => {
const info = dump.value[key];
if (!info.visible) {
return;
}
const element = panel.elements[key];
let $prop = panel.$props[key];
newPropKeys.push(key);
if (!$prop) {
if (element && element.create) {
// when it need to go custom initialize
$prop = panel.$props[key] = panel.$[key] = element.create.call(panel, info);
} else {
$prop = panel.$props[key] = panel.$[key] = document.createElement("ui-prop");
$prop.setAttribute("type", "dump");
}
const _displayOrder = info.group?.displayOrder ?? info.displayOrder;
$prop.displayOrder = _displayOrder === undefined ? index : Number(_displayOrder);
if (element && element.displayOrder !== undefined) {
$prop.displayOrder = element.displayOrder;
}
if (!element || !element.isAppendToParent || element.isAppendToParent.call(panel)) {
if (info.group && dump.groups) {
const { id = "default", name } = info.group;
if (!panel.$groups[id] && dump.groups[id]) {
if (dump.groups[id].style === "tab") {
panel.$groups[id] = exports.createTabGroup(dump.groups[id], panel);
}
}
if (panel.$groups[id]) {
if (!panel.$groups[id].isConnected) {
exports.appendChildByDisplayOrder(panel.$.componentContainer, panel.$groups[id]);
}
if (dump.groups[id].style === "tab") {
exports.appendToTabGroup(panel.$groups[id], name);
}
}
exports.appendChildByDisplayOrder(panel.$groups[id].tabs[name], $prop);
} else {
exports.appendChildByDisplayOrder(panel.$.componentContainer, $prop);
}
}
} else if (!$prop.isConnected || !$prop.parentElement) {
if (!element || !element.isAppendToParent || element.isAppendToParent.call(panel)) {
if (info.group && dump.groups) {
const { id = "default", name } = info.group;
exports.appendChildByDisplayOrder(panel.$groups[id].tabs[name], $prop);
} else {
exports.appendChildByDisplayOrder(panel.$.componentContainer, $prop);
}
}
}
$prop.render(info);
});
for (const id of oldPropKeys) {
if (!newPropKeys.includes(id)) {
const $prop = panel.$props[id];
if ($prop && $prop.parentElement) {
$prop.parentElement.removeChild($prop);
}
}
}
for (const key in panel.elements) {
const element = panel.elements[key];
if (element && element.ready) {
element.ready.call(panel, panel.$[key], dump.value);
element.ready = undefined; // ready needs to be executed only once
}
}
for (const key in panel.elements) {
const element = panel.elements[key];
if (element && element.update) {
element.update.call(panel, panel.$[key], dump.value);
}
}
exports.toggleGroups(panel.$groups);
}
/**
* Tool function: check whether the value of the attribute is consistent after multi-selection
*/
export function isMultipleInvalid(dump) {
let invalid = false;
if (dump.values && dump.values.some(ds => ds !== dump.value)) {
invalid = true;
}
return invalid;
}
/**
* Get the name based on the dump data
*/
/**
*
* @param {string} dump
* @returns
*/
export function getName(dump) {
if (!dump) {
return "";
}
if (dump.displayName) {
return dump.displayName;
}
let name = dump.name || "";
name = name.trim().replace(/^\S/, str => str.toUpperCase());
name = name.replace(/_/g, str => " ");
name = name.replace(/ \S/g, str => ` ${str.toUpperCase()}`);
// 驼峰转中间空格
name = name.replace(/([a-z])([A-Z])/g, "$1 $2");
return name.trim();
}
export function createTabGroup(dump, panel) {
const $group = document.createElement("div");
$group.setAttribute("class", "tab-group");
$group.dump = dump;
$group.tabs = {};
$group.displayOrder = dump.displayOrder;
$group.$header = document.createElement("ui-tab");
$group.$header.setAttribute("class", "tab-header");
$group.appendChild($group.$header);
$group.$header.addEventListener("change", e => {
active(e.target.value);
});
function active(index) {
const tabNames = Object.keys($group.tabs);
const tabName = tabNames[index];
$group.childNodes.forEach(child => {
if (!child.classList.contains("tab-content")) {
return;
}
if (child.getAttribute("name") === tabName) {
child.style.display = "block";
} else {
child.style.display = "none";
}
});
}
// check style
if (!panel.$this.shadowRoot.querySelector("style#group-style")) {
const style = document.createElement("style");
style.setAttribute("id", "group-style");
style.innerText = `
.tab-group {
margin-top: 10px;
margin-bottom: 10px;
}
.tab-content {
display: none;
border: 1px dashed var(--color-normal-border);
padding: 10px;
margin-top: -9px;
border-top-right-radius: calc(var(--size-normal-radius) * 1px);
border-bottom-left-radius: calc(var(--size-normal-radius) * 1px);
border-bottom-right-radius: calc(var(--size-normal-radius) * 1px);
}`;
panel.$.componentContainer.before(style);
}
setTimeout(() => {
active(0);
});
return $group;
}
export function toggleGroups($groups) {
for (const key in $groups) {
const $props = Array.from($groups[key].querySelectorAll(".tab-content > ui-prop"));
const show = $props.some($prop => getComputedStyle($prop).display !== "none");
if (show) {
$groups[key].removeAttribute("hidden");
} else {
$groups[key].setAttribute("hidden", "");
}
}
}
export function appendToTabGroup($group, tabName) {
if ($group.tabs[tabName]) {
return;
}
const $content = document.createElement("div");
$group.tabs[tabName] = $content;
$content.setAttribute("class", "tab-content");
$content.setAttribute("name", tabName);
$group.appendChild($content);
const $label = document.createElement("ui-label");
$label.value = exports.getName(tabName);
const $button = document.createElement("ui-button");
$button.setAttribute("name", tabName);
$button.appendChild($label);
$group.$header.appendChild($button);
}
export function appendChildByDisplayOrder(parent, newChild) {
const displayOrder = newChild.displayOrder || 0;
const children = Array.from(parent.children);
const child = children.find(child => {
if (child.dump && child.displayOrder > displayOrder) {
return child;
}
return null;
});
if (child) {
child.before(newChild);
} else {
parent.appendChild(newChild);
}
}

View File

@@ -0,0 +1,35 @@
let storedDirector;
let uuid: string;
/**
* @en Registration method for the main process of Extension
* @zh 为扩展的主进程的注册方法
*/
export const methods: { [key: string]: (...any: any) => any } = {
recordUuid(_uuid: string): void {
uuid = _uuid;
},
recordDirector(director: any) {
storedDirector = director;
console.log("main receive", director);
},
saveScene(){
Editor.Message.send("scene", "execute-component-method", {
uuid,
name: "saveCurrentState",
args: []
})
console.log("saveScene", arguments);
}
};
/**
* @en Hooks triggered after extension loading is complete
* @zh 扩展加载完成后触发的钩子
*/
export function load() {}
/**
* @en Hooks triggered after extension uninstallation is complete
* @zh 扩展卸载完成后触发的钩子
*/
export function unload() {}

View File

@@ -0,0 +1,30 @@
import { readFileSync } from "fs";
import { join } from "path";
module.exports = Editor.Panel.define({
listeners: {
show() {
console.log("show", arguments);
},
hide() {
console.log("hide");
}
},
template: readFileSync(join(__dirname, "../../../static/template/default/index.html"), "utf-8"),
style: "div { color: yellow; }",
$: {
btnCopy: "#btnCopy",
code: "#code"
},
methods: {
},
ready() {
if (arguments[0]) this.$.code!.innerHTML = JSON.stringify(arguments[0], null, 2);
this.$.btnCopy!.addEventListener('confirm', () => {
Editor.Clipboard.write("text", this.$.code!.innerHTML);
console.log("已复制到剪贴板!");
});
},
beforeClose() {},
close() {}
});

View File

@@ -0,0 +1,19 @@
module.exports = Editor.Panel.define({
listeners: {
show() {
console.log("show");
},
hide() {
console.log("hide");
}
},
template: "<div>Hello</div>",
style: "div { color: yellow; }",
$: {
code: "#code"
},
methods: {},
ready() {},
beforeClose() {},
close() {}
});

View File

@@ -0,0 +1,42 @@
// @ts-nocheck
import { director, Node } from "cc";
export function load() {}
export function unload() {}
export const methods = {
copyRecords(uuid: string) {
const node = this.iterateFindChildByUuid(director.getScene(), uuid);
if (!node) return null;
const uiState = node.getComponent("UIState");
if (!uiState) return null;
const cloneState = {};
Object.values(uiState.records).forEach((stateRecord, index) => {
const records = [];
stateRecord.forEach(record => {
const clone = {};
Object.assign(clone, record);
if (record.node) {
clone.uuid = record.node.uuid;
clone.name = record.node.name;
delete clone.node;
}
records.push(clone);
});
cloneState[uiState.states[index]] = records;
});
return cloneState;
},
/** 根据uuid深度优先查找节点 */
iterateFindChildByUuid(node: Node, uuid: string): Node {
for (let i = 0; i < node.children.length; i++) {
const child = node.children[i];
if (child.uuid === uuid) return child;
if (child.children?.length) {
const findNode = this.iterateFindChildByUuid(child, uuid);
if (findNode) return findNode;
}
}
return null;
}
};