From 103f773286f3317f75b597fa75a893d5e3e136f1 Mon Sep 17 00:00:00 2001 From: YHH <359807859@qq.com> Date: Mon, 16 Jun 2025 18:32:44 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0Cocos=20Creator=20ECS?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E5=99=A8=E6=8F=92=E4=BB=B6=EF=BC=9A=E5=AE=8C?= =?UTF-8?q?=E6=95=B4=E7=9A=84=E6=A1=86=E6=9E=B6=E7=AE=A1=E7=90=86=E5=92=8C?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E7=94=9F=E6=88=90=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...tom Script Template Help Documentation.url | 2 + extensions/cocos/cocos-ecs/.gitignore | 24 + extensions/cocos/cocos-ecs/assets/scenes.meta | 9 + .../cocos/cocos-ecs/assets/scenes/scene.scene | 434 ++++++++++++++ .../cocos-ecs/assets/scenes/scene.scene.meta | 11 + .../cocos/cocos-ecs/assets/scripts.meta | 9 + .../@types/schema/package/base/panels.json | 81 +++ .../schema/package/contributions/index.json | 9 + .../@types/schema/package/index.json | 64 +++ .../extensions/cocos-ecs-extension/README.md | 25 + .../cocos-ecs-extension/README.zh-CN.md | 24 + .../cocos-ecs-extension/base.tsconfig.json | 22 + .../extensions/cocos-ecs-extension/i18n/en.js | 1 + .../extensions/cocos-ecs-extension/i18n/zh.js | 1 + .../cocos-ecs-extension/package-lock.json | 287 ++++++++++ .../cocos-ecs-extension/package.json | 103 ++++ .../cocos-ecs-extension/scripts/preinstall.js | 1 + .../source/TemplateGenerator.ts | 403 +++++++++++++ .../cocos-ecs-extension/source/main.ts | 245 ++++++++ .../source/panels/default/index.ts | 533 ++++++++++++++++++ .../static/style/default/index.css | 450 +++++++++++++++ .../static/template/default/index.html | 5 + .../static/template/vue/counter.html | 6 + .../static/template/vue/welcome.html | 169 ++++++ .../cocos-ecs-extension/tsconfig.json | 11 + extensions/cocos/cocos-ecs/package-lock.json | 21 + extensions/cocos/cocos-ecs/package.json | 10 + .../settings/v2/packages/builder.json | 3 + .../settings/v2/packages/device.json | 3 + .../settings/v2/packages/engine.json | 3 + .../settings/v2/packages/information.json | 23 + .../settings/v2/packages/program.json | 3 + .../settings/v2/packages/project.json | 3 + extensions/cocos/cocos-ecs/tsconfig.json | 9 + 34 files changed, 3007 insertions(+) create mode 100644 extensions/cocos/cocos-ecs/.creator/asset-template/typescript/Custom Script Template Help Documentation.url create mode 100644 extensions/cocos/cocos-ecs/.gitignore create mode 100644 extensions/cocos/cocos-ecs/assets/scenes.meta create mode 100644 extensions/cocos/cocos-ecs/assets/scenes/scene.scene create mode 100644 extensions/cocos/cocos-ecs/assets/scenes/scene.scene.meta create mode 100644 extensions/cocos/cocos-ecs/assets/scripts.meta create mode 100644 extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/@types/schema/package/base/panels.json create mode 100644 extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/@types/schema/package/contributions/index.json create mode 100644 extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/@types/schema/package/index.json create mode 100644 extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/README.md create mode 100644 extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/README.zh-CN.md create mode 100644 extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/base.tsconfig.json create mode 100644 extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/i18n/en.js create mode 100644 extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/i18n/zh.js create mode 100644 extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/package-lock.json create mode 100644 extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/package.json create mode 100644 extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/scripts/preinstall.js create mode 100644 extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/source/TemplateGenerator.ts create mode 100644 extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/source/main.ts create mode 100644 extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/source/panels/default/index.ts create mode 100644 extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/style/default/index.css create mode 100644 extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/template/default/index.html create mode 100644 extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/template/vue/counter.html create mode 100644 extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/template/vue/welcome.html create mode 100644 extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/tsconfig.json create mode 100644 extensions/cocos/cocos-ecs/package-lock.json create mode 100644 extensions/cocos/cocos-ecs/package.json create mode 100644 extensions/cocos/cocos-ecs/settings/v2/packages/builder.json create mode 100644 extensions/cocos/cocos-ecs/settings/v2/packages/device.json create mode 100644 extensions/cocos/cocos-ecs/settings/v2/packages/engine.json create mode 100644 extensions/cocos/cocos-ecs/settings/v2/packages/information.json create mode 100644 extensions/cocos/cocos-ecs/settings/v2/packages/program.json create mode 100644 extensions/cocos/cocos-ecs/settings/v2/packages/project.json create mode 100644 extensions/cocos/cocos-ecs/tsconfig.json diff --git a/extensions/cocos/cocos-ecs/.creator/asset-template/typescript/Custom Script Template Help Documentation.url b/extensions/cocos/cocos-ecs/.creator/asset-template/typescript/Custom Script Template Help Documentation.url new file mode 100644 index 00000000..7606df06 --- /dev/null +++ b/extensions/cocos/cocos-ecs/.creator/asset-template/typescript/Custom Script Template Help Documentation.url @@ -0,0 +1,2 @@ +[InternetShortcut] +URL=https://docs.cocos.com/creator/manual/en/scripting/setup.html#custom-script-template \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/.gitignore b/extensions/cocos/cocos-ecs/.gitignore new file mode 100644 index 00000000..a231b3f5 --- /dev/null +++ b/extensions/cocos/cocos-ecs/.gitignore @@ -0,0 +1,24 @@ + +#/////////////////////////// +# Cocos Creator 3D Project +#/////////////////////////// +library/ +temp/ +local/ +build/ +profiles/ +native +#////////////////////////// +# NPM +#////////////////////////// +node_modules/ + +#////////////////////////// +# VSCode +#////////////////////////// +.vscode/ + +#////////////////////////// +# WebStorm +#////////////////////////// +.idea/ \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/scenes.meta b/extensions/cocos/cocos-ecs/assets/scenes.meta new file mode 100644 index 00000000..25614c04 --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/scenes.meta @@ -0,0 +1,9 @@ +{ + "ver": "1.2.0", + "importer": "directory", + "imported": true, + "uuid": "e7a0c4c4-f555-4dc5-be34-83ae26b4eb35", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/extensions/cocos/cocos-ecs/assets/scenes/scene.scene b/extensions/cocos/cocos-ecs/assets/scenes/scene.scene new file mode 100644 index 00000000..51798289 --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/scenes/scene.scene @@ -0,0 +1,434 @@ +[ + { + "__type__": "cc.SceneAsset", + "_name": "scene", + "_objFlags": 0, + "__editorExtras__": {}, + "_native": "", + "scene": { + "__id__": 1 + } + }, + { + "__type__": "cc.Scene", + "_name": "scene", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": null, + "_children": [ + { + "__id__": 2 + }, + { + "__id__": 5 + } + ], + "_active": true, + "_components": [], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_lrot": { + "__type__": "cc.Quat", + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "_lscale": { + "__type__": "cc.Vec3", + "x": 1, + "y": 1, + "z": 1 + }, + "_mobility": 0, + "_layer": 1073741824, + "_euler": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "autoReleaseAssets": false, + "_globals": { + "__id__": 7 + }, + "_id": "ff354f0b-c2f5-4dea-8ffb-0152d175d11c" + }, + { + "__type__": "cc.Node", + "_name": "Main Light", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 1 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 3 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_lrot": { + "__type__": "cc.Quat", + "x": -0.06397656665577071, + "y": -0.44608233363525845, + "z": -0.8239028751062036, + "w": -0.3436591377065261 + }, + "_lscale": { + "__type__": "cc.Vec3", + "x": 1, + "y": 1, + "z": 1 + }, + "_mobility": 0, + "_layer": 1073741824, + "_euler": { + "__type__": "cc.Vec3", + "x": -117.894, + "y": -194.909, + "z": 38.562 + }, + "_id": "c0y6F5f+pAvI805TdmxIjx" + }, + { + "__type__": "cc.DirectionalLight", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 2 + }, + "_enabled": true, + "__prefab": null, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 250, + "b": 240, + "a": 255 + }, + "_useColorTemperature": false, + "_colorTemperature": 6550, + "_staticSettings": { + "__id__": 4 + }, + "_visibility": -325058561, + "_illuminanceHDR": 65000, + "_illuminance": 65000, + "_illuminanceLDR": 1.6927083333333335, + "_shadowEnabled": false, + "_shadowPcf": 0, + "_shadowBias": 0.00001, + "_shadowNormalBias": 0, + "_shadowSaturation": 1, + "_shadowDistance": 50, + "_shadowInvisibleOcclusionRange": 200, + "_csmLevel": 4, + "_csmLayerLambda": 0.75, + "_csmOptimizationMode": 2, + "_csmAdvancedOptions": false, + "_csmLayersTransition": false, + "_csmTransitionRange": 0.05, + "_shadowFixedArea": false, + "_shadowNear": 0.1, + "_shadowFar": 10, + "_shadowOrthoSize": 5, + "_id": "597uMYCbhEtJQc0ffJlcgA" + }, + { + "__type__": "cc.StaticLightSettings", + "_baked": false, + "_editorOnly": false, + "_castShadow": false + }, + { + "__type__": "cc.Node", + "_name": "Main Camera", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 1 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 6 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": -10, + "y": 10, + "z": 10 + }, + "_lrot": { + "__type__": "cc.Quat", + "x": -0.27781593346944056, + "y": -0.36497167621709875, + "z": -0.11507512748638377, + "w": 0.8811195706053617 + }, + "_lscale": { + "__type__": "cc.Vec3", + "x": 1, + "y": 1, + "z": 1 + }, + "_mobility": 0, + "_layer": 1073741824, + "_euler": { + "__type__": "cc.Vec3", + "x": -35, + "y": -45, + "z": 0 + }, + "_id": "c9DMICJLFO5IeO07EPon7U" + }, + { + "__type__": "cc.Camera", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 5 + }, + "_enabled": true, + "__prefab": null, + "_projection": 1, + "_priority": 0, + "_fov": 45, + "_fovAxis": 0, + "_orthoHeight": 10, + "_near": 1, + "_far": 1000, + "_color": { + "__type__": "cc.Color", + "r": 51, + "g": 51, + "b": 51, + "a": 255 + }, + "_depth": 1, + "_stencil": 0, + "_clearFlags": 14, + "_rect": { + "__type__": "cc.Rect", + "x": 0, + "y": 0, + "width": 1, + "height": 1 + }, + "_aperture": 19, + "_shutter": 7, + "_iso": 0, + "_screenScale": 1, + "_visibility": 1822425087, + "_targetTexture": null, + "_postProcess": null, + "_usePostProcess": false, + "_cameraType": -1, + "_trackingType": 0, + "_id": "7dWQTpwS5LrIHnc1zAPUtf" + }, + { + "__type__": "cc.SceneGlobals", + "ambient": { + "__id__": 8 + }, + "shadows": { + "__id__": 9 + }, + "_skybox": { + "__id__": 10 + }, + "fog": { + "__id__": 11 + }, + "octree": { + "__id__": 12 + }, + "skin": { + "__id__": 13 + }, + "lightProbeInfo": { + "__id__": 14 + }, + "postSettings": { + "__id__": 15 + }, + "bakedWithStationaryMainLight": false, + "bakedWithHighpLightmap": false + }, + { + "__type__": "cc.AmbientInfo", + "_skyColorHDR": { + "__type__": "cc.Vec4", + "x": 0.2, + "y": 0.5, + "z": 0.8, + "w": 0.520833125 + }, + "_skyColor": { + "__type__": "cc.Vec4", + "x": 0.2, + "y": 0.5, + "z": 0.8, + "w": 0.520833125 + }, + "_skyIllumHDR": 20000, + "_skyIllum": 20000, + "_groundAlbedoHDR": { + "__type__": "cc.Vec4", + "x": 0.2, + "y": 0.2, + "z": 0.2, + "w": 1 + }, + "_groundAlbedo": { + "__type__": "cc.Vec4", + "x": 0.2, + "y": 0.2, + "z": 0.2, + "w": 1 + }, + "_skyColorLDR": { + "__type__": "cc.Vec4", + "x": 0.452588, + "y": 0.607642, + "z": 0.755699, + "w": 0 + }, + "_skyIllumLDR": 0.8, + "_groundAlbedoLDR": { + "__type__": "cc.Vec4", + "x": 0.618555, + "y": 0.577848, + "z": 0.544564, + "w": 0 + } + }, + { + "__type__": "cc.ShadowsInfo", + "_enabled": false, + "_type": 0, + "_normal": { + "__type__": "cc.Vec3", + "x": 0, + "y": 1, + "z": 0 + }, + "_distance": 0, + "_planeBias": 1, + "_shadowColor": { + "__type__": "cc.Color", + "r": 76, + "g": 76, + "b": 76, + "a": 255 + }, + "_maxReceived": 4, + "_size": { + "__type__": "cc.Vec2", + "x": 1024, + "y": 1024 + } + }, + { + "__type__": "cc.SkyboxInfo", + "_envLightingType": 0, + "_envmapHDR": { + "__uuid__": "d032ac98-05e1-4090-88bb-eb640dcb5fc1@b47c0", + "__expectedType__": "cc.TextureCube" + }, + "_envmap": { + "__uuid__": "d032ac98-05e1-4090-88bb-eb640dcb5fc1@b47c0", + "__expectedType__": "cc.TextureCube" + }, + "_envmapLDR": { + "__uuid__": "6f01cf7f-81bf-4a7e-bd5d-0afc19696480@b47c0", + "__expectedType__": "cc.TextureCube" + }, + "_diffuseMapHDR": null, + "_diffuseMapLDR": null, + "_enabled": true, + "_useHDR": true, + "_editableMaterial": null, + "_reflectionHDR": null, + "_reflectionLDR": null, + "_rotationAngle": 0 + }, + { + "__type__": "cc.FogInfo", + "_type": 0, + "_fogColor": { + "__type__": "cc.Color", + "r": 200, + "g": 200, + "b": 200, + "a": 255 + }, + "_enabled": false, + "_fogDensity": 0.3, + "_fogStart": 0.5, + "_fogEnd": 300, + "_fogAtten": 5, + "_fogTop": 1.5, + "_fogRange": 1.2, + "_accurate": false + }, + { + "__type__": "cc.OctreeInfo", + "_enabled": false, + "_minPos": { + "__type__": "cc.Vec3", + "x": -1024, + "y": -1024, + "z": -1024 + }, + "_maxPos": { + "__type__": "cc.Vec3", + "x": 1024, + "y": 1024, + "z": 1024 + }, + "_depth": 8 + }, + { + "__type__": "cc.SkinInfo", + "_enabled": true, + "_blurRadius": 0.01, + "_sssIntensity": 3 + }, + { + "__type__": "cc.LightProbeInfo", + "_giScale": 1, + "_giSamples": 1024, + "_bounces": 2, + "_reduceRinging": 0, + "_showProbe": true, + "_showWireframe": true, + "_showConvex": false, + "_data": null, + "_lightProbeSphereVolume": 1 + }, + { + "__type__": "cc.PostSettingsInfo", + "_toneMappingType": 0 + } +] \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/scenes/scene.scene.meta b/extensions/cocos/cocos-ecs/assets/scenes/scene.scene.meta new file mode 100644 index 00000000..b2556a95 --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/scenes/scene.scene.meta @@ -0,0 +1,11 @@ +{ + "ver": "1.1.50", + "importer": "scene", + "imported": true, + "uuid": "ff354f0b-c2f5-4dea-8ffb-0152d175d11c", + "files": [ + ".json" + ], + "subMetas": {}, + "userData": {} +} diff --git a/extensions/cocos/cocos-ecs/assets/scripts.meta b/extensions/cocos/cocos-ecs/assets/scripts.meta new file mode 100644 index 00000000..a388a128 --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/scripts.meta @@ -0,0 +1,9 @@ +{ + "ver": "1.2.0", + "importer": "directory", + "imported": true, + "uuid": "1bf5f009-19d9-42b9-b6bb-b44efe349b09", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/@types/schema/package/base/panels.json b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/@types/schema/package/base/panels.json new file mode 100644 index 00000000..9e268fba --- /dev/null +++ b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/@types/schema/package/base/panels.json @@ -0,0 +1,81 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "description": "面板数据 / Panel data", + "additionalProperties": false, + "patternProperties": { + "^[a-zA-Z0-9_-]+$": { + "type": "object", + "description": "面板名 / Panel name", + "properties": { + "title": { + "type": "string", + "default": "Default Panel", + "description": "面板标题,支持 i18n:key / Panel title, support for i18n:key (required)" + }, + "main": { + "type": "string", + "default": "dist/panels/default/index.js", + "description": "入口函数 / Entry function (required)" + }, + "icon": { + "type": "string", + "description": "面板图标存放相对目录 / Relative directory for panel icon storage" + }, + "type": { + "type": "string", + "enum": ["dockable", "simple"], + "default": "dockable", + "description": "面板类型(dockable | simple) / Panel type (dockable | simple)" + }, + "flags": { + "type": "object", + "properties": { + "resizable": { + "type": "boolean", + "default": true, + "description": "是否可以改变大小,默认 true / Whether the size can be changed, default true" + }, + "save": { + "type": "boolean", + "default": true, + "description": "是否需要保存,默认 false / Whether to save, default false" + }, + "alwaysOnTop": { + "type": "boolean", + "default": true, + "description": "是否保持顶层显示,默认 false / Whether to keep the top level display, default false" + } + } + }, + "size": { + "type": "object", + "description": "面板大小信息 / Panel size information", + "properties": { + "min-width": { + "type": "number", + "default": 200, + "description": "面板最小宽度 / Minimum panel width" + }, + "min-height": { + "type": "number", + "default": 200, + "description": "面板最小高度 / Minimum panel height" + }, + "width": { + "type": "number", + "default": 400, + "description": " 面板默认宽度 / Panel Default Width" + }, + "height": { + "type": "number", + "default": 600, + "description": "面板默认高度 / Panel Default Height" + } + } + } + }, + "required": ["title", "main"] + } + } +} diff --git a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/@types/schema/package/contributions/index.json b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/@types/schema/package/contributions/index.json new file mode 100644 index 00000000..185ad85f --- /dev/null +++ b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/@types/schema/package/contributions/index.json @@ -0,0 +1,9 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "description": "其他扩展插件的扩展配置 / Extended configuration for other extension plugins", + "properties": { + + }, + "required": [] +} diff --git a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/@types/schema/package/index.json b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/@types/schema/package/index.json new file mode 100644 index 00000000..0452158b --- /dev/null +++ b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/@types/schema/package/index.json @@ -0,0 +1,64 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "description": "插件定义文件 / Extension definition file", + "properties": { + "author": { + "type": "string", + "description": "作者 / Author", + "default": "Cocos Creator Developer" + }, + "contributions": { + "$ref": "./contributions/index.json" + }, + "dependencies": { + "type": "object", + "description": "发布时所需的依赖库 / Dependencies required for publishing" + }, + "description": { + "type": "string", + "description": "简要介绍扩展关键特性、用途,支持 i18n / Brief introduction of the key features and uses of the extension, supporting i18n" + }, + "devDependencies": { + "type": "object", + "description": "开发时所需的依赖库 / Dependencies required for development" + }, + "editor": { + "type": "string", + "description": "支持的 Cocos Creator 编辑器版本,支持 semver 格式 / Supported Cocos Creator editor version, supporting semver format" + }, + "main": { + "type": "string", + "description": "入口函数 / Entry function", + "default": "./dist/index.js" + }, + "name": { + "type": "string", + "description": "不能以 _ 或 . 开头、不能含有大写字母,也不能含有 URL 的非法字符例如 .、' 和 ,。 / Cannot start with _ or., cannot contain uppercase letters, and cannot contain URL illegal characters such as.,'and,", + "default": "Custom Extension" + }, + "package_version": { + "type": "number", + "description": "扩展系统预留版本号 / Extension system reserved version number", + "default": 2 + }, + "panels": { + "$ref": "./base/panels.json" + }, + "scripts": { + "type": "object", + "description": "NPM 脚本 / NPM scripts" + }, + "version": { + "type": "string", + "description": "版本号字符串 / Version number string", + "default": "1.0.0" + } + }, + "required": [ + "author", + "name", + "package_version", + "version" + ] +} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/README.md b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/README.md new file mode 100644 index 00000000..4f713e6d --- /dev/null +++ b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/README.md @@ -0,0 +1,25 @@ +# Project Title + +An extension that shows how to open and communicate with the panel through messages and menus. +The panel is based on Vue3.x. + +## Development Environment + +Node.js + +## Install + +```bash +# Install dependent modules +npm install +# build +npm run build +``` + +## Usage + +After enabling the extension, click `Panel -> cocos-ecs-extension -> Default Panel` in the main menu bar to open the default panel of the extension. + +To send a message to the default panel, click `Developer -> cocos-ecs-extension -> Send Message to Panel` at the top of the menu. If the default panel exists, the `hello` method of the panel will be called. + +After clicking `Send Message to Panel`, a message `send-to-panel` will be sent to the extension as defined by `contributions.menu` in `package.json`. When the extension receives the `send-to-panel` message, it will cause the `default` panel to call the `hello` method as defined by `contributions.messages` in `package.json`. diff --git a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/README.zh-CN.md b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/README.zh-CN.md new file mode 100644 index 00000000..487ea877 --- /dev/null +++ b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/README.zh-CN.md @@ -0,0 +1,24 @@ +# 项目简介 + +一份包含面板的扩展,该面板基于 vue3.x 开发,展示了如何通过消息和菜单打开面板,以及与面板通讯。 + +## 开发环境 + +Node.js + +## 安装 + +```bash +# 安装依赖模块 +npm install +# 构建 +npm run build +``` + +## 用法 + +启用扩展后,点击主菜单栏中的 `面板 -> cocos-ecs-extension -> 默认面板`,即可打开扩展的默认面板。 + +依次点击顶部菜单的 `开发者 -> cocos-ecs-extension -> 发送消息给面板` 即可发送消息给默认面板,如果此时存在默认面板,将会调用面板的 `hello` 方法。 + +点击 `发送消息给面板` 后,根据 `package.json` 中 `contributions.menu` 的定义将发送一条消息 `send-to-panel` 给扩展。根据 `package.json` 中 `contributions.messages` 的定义当扩展收到 `send-to-panel` 后将会使 `default` 面板调用 `hello` 方法。 diff --git a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/base.tsconfig.json b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/base.tsconfig.json new file mode 100644 index 00000000..6fd63022 --- /dev/null +++ b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/base.tsconfig.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/tsconfig.json", + "compilerOptions": { + "target": "ES2017", + "module": "CommonJS", + "moduleResolution": "node", + "inlineSourceMap": true, + "inlineSources": true, + "esModuleInterop": true, + "skipLibCheck": true, + "strict": true, + "experimentalDecorators": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "outDir": "./dist", + "rootDir": "./source", + "types": [ + "node", + "@cocos/creator-types/editor", + ] + } +} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/i18n/en.js b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/i18n/en.js new file mode 100644 index 00000000..1b1ffa76 --- /dev/null +++ b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/i18n/en.js @@ -0,0 +1 @@ +"use strict";module.exports={open_panel:"Default Panel",send_to_panel:"Send message to Default Panel",description:"Extension with a panel based on Vue3.x"}; \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/i18n/zh.js b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/i18n/zh.js new file mode 100644 index 00000000..ead340af --- /dev/null +++ b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/i18n/zh.js @@ -0,0 +1 @@ +"use strict";module.exports={open_panel:"默认面板",send_to_panel:"发送消息给面板",description:"含有一个基于Vue3.x开发的面板的扩展"}; \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/package-lock.json b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/package-lock.json new file mode 100644 index 00000000..6bef86e9 --- /dev/null +++ b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/package-lock.json @@ -0,0 +1,287 @@ +{ + "name": "cocos-ecs-extension", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "cocos-ecs-extension", + "version": "1.0.0", + "hasInstallScript": true, + "dependencies": { + "fs-extra": "^10.0.0", + "vue": "^3.1.4" + }, + "devDependencies": { + "@cocos/creator-types": "^3.8.6", + "@types/fs-extra": "^9.0.5", + "@types/node": "^18.17.1", + "typescript": "^5.8.2" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.0", + "license": "MIT", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@cocos/creator-types": { + "version": "3.8.6", + "resolved": "https://registry.npmjs.org/@cocos/creator-types/-/creator-types-3.8.6.tgz", + "integrity": "sha512-hyZ4aoqqLxoRtKbBLSJM5RgtK3oGOlTEryHDcyH4znq3h9cFk+MSbQC2aJHvK5/bMlJzsZ641/hD77RGSrvo8Q==", + "dev": true + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "license": "MIT" + }, + "node_modules/@types/fs-extra": { + "version": "9.0.13", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "18.19.111", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.111.tgz", + "integrity": "sha512-90sGdgA+QLJr1F9X79tQuEut0gEYIfkX9pydI4XGRgvFo9g2JWswefI+WUSUHPYVBHYSEfTEqBxA5hQvAZB3Mw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.3.4", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.21.3", + "@vue/shared": "3.3.4", + "estree-walker": "^2.0.2", + "source-map-js": "^1.0.2" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.3.4", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.3.4", + "@vue/shared": "3.3.4" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.3.4", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.15", + "@vue/compiler-core": "3.3.4", + "@vue/compiler-dom": "3.3.4", + "@vue/compiler-ssr": "3.3.4", + "@vue/reactivity-transform": "3.3.4", + "@vue/shared": "3.3.4", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.0", + "postcss": "^8.1.10", + "source-map-js": "^1.0.2" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.3.4", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.3.4", + "@vue/shared": "3.3.4" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.3.4", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.3.4" + } + }, + "node_modules/@vue/reactivity-transform": { + "version": "3.3.4", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.15", + "@vue/compiler-core": "3.3.4", + "@vue/shared": "3.3.4", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.0" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.3.4", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.3.4", + "@vue/shared": "3.3.4" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.3.4", + "license": "MIT", + "dependencies": { + "@vue/runtime-core": "3.3.4", + "@vue/shared": "3.3.4", + "csstype": "^3.1.1" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.3.4", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.3.4", + "@vue/shared": "3.3.4" + }, + "peerDependencies": { + "vue": "3.3.4" + } + }, + "node_modules/@vue/shared": { + "version": "3.3.4", + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.1.2", + "license": "MIT" + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "license": "MIT" + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "license": "ISC" + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/magic-string": { + "version": "0.30.3", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/nanoid": { + "version": "3.3.6", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.4.30", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/universalify": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/vue": { + "version": "3.3.4", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.3.4", + "@vue/compiler-sfc": "3.3.4", + "@vue/runtime-dom": "3.3.4", + "@vue/server-renderer": "3.3.4", + "@vue/shared": "3.3.4" + } + } + } +} diff --git a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/package.json b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/package.json new file mode 100644 index 00000000..ecc91b33 --- /dev/null +++ b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/package.json @@ -0,0 +1,103 @@ +{ + "$schema": "./@types/schema/package/index.json", + "package_version": 2, + "name": "cocos-ecs-extension", + "version": "1.0.0", + "author": "esengine", + "editor": ">=3.8.6", + "scripts": { + "preinstall": "node ./scripts/preinstall.js", + "build": "npx tsc" + }, + "description": "i18n:cocos-ecs-extension.description", + "main": "./dist/main.js", + "dependencies": { + "vue": "^3.1.4", + "fs-extra": "^10.0.0" + }, + "devDependencies": { + "@cocos/creator-types": "^3.8.6", + "@types/fs-extra": "^9.0.5", + "@types/node": "^18.17.1", + "typescript": "^5.8.2" + }, + "panels": { + "default": { + "title": "ECS Framework - 欢迎面板", + "type": "dockable", + "main": "dist/panels/default", + "size": { + "min-width": 450, + "min-height": 600, + "width": 850, + "height": 800 + } + } + }, + "contributions": { + "menu": [ + { + "path": "i18n:menu.panel/ECS Framework", + "label": "欢迎面板", + "message": "open-panel" + }, + { + "path": "i18n:menu.develop/ECS Framework", + "label": "ECS 开发工具", + "message": "open-panel" + } + ], + "messages": { + "open-panel": { + "methods": [ + "openPanel" + ] + }, + "install-ecs-framework": { + "methods": [ + "install-ecs-framework" + ] + }, + "update-ecs-framework": { + "methods": [ + "update-ecs-framework" + ] + }, + "uninstall-ecs-framework": { + "methods": [ + "uninstall-ecs-framework" + ] + }, + "open-documentation": { + "methods": [ + "open-documentation" + ] + }, + "create-ecs-template": { + "methods": [ + "create-ecs-template" + ] + }, + "open-settings": { + "methods": [ + "open-settings" + ] + }, + "open-project-analysis": { + "methods": [ + "open-project-analysis" + ] + }, + "open-component-library": { + "methods": [ + "open-component-library" + ] + }, + "open-github": { + "methods": [ + "open-github" + ] + } + } + } +} diff --git a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/scripts/preinstall.js b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/scripts/preinstall.js new file mode 100644 index 00000000..3876bba6 --- /dev/null +++ b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/scripts/preinstall.js @@ -0,0 +1 @@ +const readFileSync=require("fs")["readFileSync"],join=require("path")["join"],spawnSync=require("child_process")["spawnSync"],PATH={packageJSON:join(__dirname,"../package.json")};function checkCreatorTypesVersion(e){var o="win32"===process.platform?"npm.cmd":"npm";let n=spawnSync(o,["view","@cocos/creator-types","versions"]).stdout.toString();try{n=JSON.parse(listString)}catch(e){}return!!n.includes(e)}try{const e=readFileSync(PATH.packageJSON,"utf8"),f=JSON.parse(e),g=f.devDependencies["@cocos/creator-types"].replace(/^[^\d]+/,"");checkCreatorTypesVersion(g)||(console.log("Warning:"),console.log(" @en"),console.log(" Version check of @cocos/creator-types failed."),console.log(` The definition of ${g} has not been released yet. Please export the definition to the ./node_modules directory by selecting "Developer -> Export Interface Definition" in the menu of the Creator editor.`),console.log(" The definition of the corresponding version will be released on npm after the editor is officially released."),console.log(" @zh"),console.log(" @cocos/creator-types 版本检查失败。"),console.log(` ${g} 定义还未发布,请先通过 Creator 编辑器菜单 "开发者 -> 导出接口定义",导出定义到 ./node_modules 目录。`),console.log(" 对应版本的定义会在编辑器正式发布后同步发布到 npm 上。"))}catch(e){console.error(e)} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/source/TemplateGenerator.ts b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/source/TemplateGenerator.ts new file mode 100644 index 00000000..2d859463 --- /dev/null +++ b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/source/TemplateGenerator.ts @@ -0,0 +1,403 @@ +import * as path from 'path'; +import * as fs from 'fs'; + +/** + * ECS启动模板生成器 + * 生成最基础的ECS框架启动模板,不包含业务逻辑 + */ +export class TemplateGenerator { + private projectPath: string; + private ecsDir: string; + + constructor(projectPath: string) { + this.projectPath = projectPath; + this.ecsDir = path.join(projectPath, 'assets', 'scripts', 'ecs'); + } + + /** + * 检查是否已经存在ECS模板 + */ + public checkTemplateExists(): boolean { + return fs.existsSync(this.ecsDir); + } + + /** + * 获取已存在的文件列表 + */ + public getExistingFiles(): string[] { + if (!this.checkTemplateExists()) return []; + + const files: string[] = []; + this.scanDirectory(this.ecsDir, '', files); + return files; + } + + private scanDirectory(dirPath: string, relativePath: string, files: string[]): void { + if (!fs.existsSync(dirPath)) return; + + const items = fs.readdirSync(dirPath); + for (const item of items) { + const fullPath = path.join(dirPath, item); + const relativeFilePath = relativePath ? `${relativePath}/${item}` : item; + + if (fs.statSync(fullPath).isDirectory()) { + this.scanDirectory(fullPath, relativeFilePath, files); + } else { + files.push(relativeFilePath); + } + } + } + + /** + * 删除现有的ECS模板 + */ + public removeExistingTemplate(): void { + if (fs.existsSync(this.ecsDir)) { + fs.rmSync(this.ecsDir, { recursive: true, force: true }); + console.log('Removed existing ECS template'); + } + } + + /** + * 创建ECS启动模板 + */ + public createTemplate(): void { + // 创建目录结构 + this.createDirectories(); + + // 创建ECS启动管理器 + this.createECSManager(); + + // 创建基础游戏场景 + this.createBaseGameScene(); + + // 创建README文档 + this.createReadme(); + + console.log('ECS启动模板创建成功'); + } + + /** + * 创建目录结构 + */ + private createDirectories(): void { + const dirs = [ + this.ecsDir, + path.join(this.ecsDir, 'scenes'), + path.join(this.ecsDir, 'components'), + path.join(this.ecsDir, 'systems') + ]; + + dirs.forEach(dir => { + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + console.log(`Created directory: ${path.relative(this.projectPath, dir)}`); + } + }); + } + + /** + * 创建ECS管理器 + */ + private createECSManager(): void { + this.writeFile(path.join(this.ecsDir, 'ECSManager.ts'), `import { Core } from '@esengine/ecs-framework'; +import { Component, _decorator } from 'cc'; +import { GameScene } from './scenes/GameScene'; + +const { ccclass, property } = _decorator; + +/** + * ECS管理器 - Cocos Creator组件 + * 将此组件添加到场景中的任意节点上即可启动ECS框架 + * + * 使用说明: + * 1. 在Cocos Creator场景中创建一个空节点 + * 2. 将此ECSManager组件添加到该节点 + * 3. 运行场景即可自动启动ECS框架 + */ +@ccclass('ECSManager') +export class ECSManager extends Component { + + @property({ + tooltip: '是否启用调试模式(建议开发阶段开启)' + }) + public debugMode: boolean = true; + + private isInitialized: boolean = false; + + /** + * 组件启动时初始化ECS + */ + start() { + this.initializeECS(); + } + + /** + * 初始化ECS框架 + */ + private initializeECS(): void { + if (this.isInitialized) return; + + console.log('🎮 正在初始化ECS框架...'); + + try { + // 1. 创建Core实例 + Core.create(this.debugMode); + + // 2. 创建游戏场景 + const gameScene = new GameScene(); + + // 3. 设置为当前场景(会自动调用scene.begin()) + Core.scene = gameScene; + + this.isInitialized = true; + console.log('✅ ECS框架初始化成功!'); + console.log('📖 请查看 assets/scripts/ecs/README.md 了解如何添加组件和系统'); + + } catch (error) { + console.error('❌ ECS框架初始化失败:', error); + } + } + + /** + * 每帧更新ECS框架 + */ + update(deltaTime: number) { + if (this.isInitialized) { + // 更新ECS核心系统 + Core.update(deltaTime); + } + } + + /** + * 组件销毁时清理ECS + */ + onDestroy() { + if (this.isInitialized) { + console.log('🧹 清理ECS框架...'); + // ECS框架会自动处理场景清理 + this.isInitialized = false; + } + } +} +`); + } + + /** + * 创建基础游戏场景 + */ + private createBaseGameScene(): void { + this.writeFile(path.join(this.ecsDir, 'scenes', 'GameScene.ts'), `import { Scene } from '@esengine/ecs-framework'; + +/** + * 游戏场景 + * + * 这是您的主游戏场景。在这里可以: + * - 添加游戏系统 + * - 创建初始实体 + * - 设置场景参数 + */ +export class GameScene extends Scene { + + /** + * 场景初始化 + * 在场景创建时调用,用于设置基础配置 + */ + public initialize(): void { + super.initialize(); + + // 设置场景名称 + this.name = "MainGameScene"; + + console.log('🎯 游戏场景已创建'); + + // TODO: 在这里添加您的游戏系统 + // 例如:this.addEntityProcessor(new MovementSystem()); + + // TODO: 在这里创建初始实体 + // 例如:this.createEntity("Player"); + } + + /** + * 场景开始运行 + * 在场景开始时调用,用于执行启动逻辑 + */ + public onStart(): void { + super.onStart(); + + console.log('🚀 游戏场景已启动'); + + // TODO: 在这里添加场景启动逻辑 + // 例如:创建UI、播放音乐、初始化游戏状态等 + } + + /** + * 场景卸载 + * 在场景结束时调用,用于清理资源 + */ + public unload(): void { + console.log('🛑 游戏场景已结束'); + + // TODO: 在这里添加清理逻辑 + // 例如:清理缓存、释放资源等 + + super.unload(); + } +} +`); + } + + /** + * 创建README文档 + */ + private createReadme(): void { + this.writeFile(path.join(this.ecsDir, 'README.md'), `# ECS框架启动模板 + +欢迎使用ECS框架!这是一个最基础的启动模板,帮助您快速开始ECS项目开发。 + +## 📁 项目结构 + +\`\`\` +ecs/ +├── components/ # 组件目录(请在此添加您的组件) +├── systems/ # 系统目录(请在此添加您的系统) +├── scenes/ # 场景目录 +│ └── GameScene.ts # 主游戏场景 +├── ECSManager.ts # ECS管理器组件 +└── README.md # 本文档 +\`\`\` + +## 🚀 快速开始 + +### 1. 启动ECS框架 + +ECS框架已经配置完成!您只需要: + +1. 在Cocos Creator中打开您的场景 +2. 创建一个空节点(例如命名为"ECSManager") +3. 将 \`ECSManager\` 组件添加到该节点 +4. 运行场景,ECS框架将自动启动 + +### 2. 查看控制台输出 + +如果一切正常,您将在控制台看到: + +\`\`\` +🎮 正在初始化ECS框架... +🎯 游戏场景已创建 +✅ ECS框架初始化成功! +🚀 游戏场景已启动 +\`\`\` + +## 📚 下一步开发 + +### 创建您的第一个组件 + +在 \`components/\` 目录下创建组件: + +\`\`\`typescript +// components/PositionComponent.ts +import { Component } from '@esengine/ecs-framework'; +import { Vec3 } from 'cc'; + +export class PositionComponent extends Component { + public position: Vec3 = new Vec3(); + + constructor(x: number = 0, y: number = 0, z: number = 0) { + super(); + this.position.set(x, y, z); + } +} +\`\`\` + +### 创建您的第一个系统 + +在 \`systems/\` 目录下创建系统: + +\`\`\`typescript +// systems/MovementSystem.ts +import { EntitySystem, Entity, Matcher } from '@esengine/ecs-framework'; +import { PositionComponent } from '../components/PositionComponent'; + +export class MovementSystem extends EntitySystem { + constructor() { + super(Matcher.empty().all(PositionComponent)); + } + + protected process(entities: Entity[]): void { + for (const entity of entities) { + const position = entity.getComponent(PositionComponent); + if (position) { + // TODO: 在这里编写移动逻辑 + console.log(\`实体 \${entity.name} 位置: \${position.position}\`); + } + } + } +} +\`\`\` + +### 在场景中注册系统 + +在 \`scenes/GameScene.ts\` 的 \`initialize()\` 方法中添加: + +\`\`\`typescript +import { MovementSystem } from '../systems/MovementSystem'; + +public initialize(): void { + super.initialize(); + this.name = "MainGameScene"; + + // 添加系统 + this.addEntityProcessor(new MovementSystem()); + + // 创建测试实体 + const testEntity = this.createEntity("TestEntity"); + testEntity.addComponent(new PositionComponent(0, 0, 0)); +} +\`\`\` + +## 🔗 学习资源 + +- [ECS框架完整文档](https://github.com/esengine/ecs-framework) +- [ECS概念详解](https://github.com/esengine/ecs-framework/blob/master/docs/concepts-explained.md) +- [新手教程](https://github.com/esengine/ecs-framework/blob/master/docs/beginner-tutorials.md) +- [组件设计指南](https://github.com/esengine/ecs-framework/blob/master/docs/component-design-guide.md) +- [系统开发指南](https://github.com/esengine/ecs-framework/blob/master/docs/system-guide.md) + +## 💡 开发提示 + +1. **组件只存储数据**:避免在组件中编写复杂逻辑 +2. **系统处理逻辑**:所有业务逻辑应该在系统中实现 +3. **使用Matcher过滤实体**:系统通过Matcher指定需要处理的实体类型 +4. **性能优化**:大量实体时考虑使用位掩码查询和组件索引 + +## ❓ 常见问题 + +### Q: 如何创建实体? +A: 在场景中使用 \`this.createEntity("实体名称")\` + +### Q: 如何给实体添加组件? +A: 使用 \`entity.addComponent(new YourComponent())\` + +### Q: 如何获取实体的组件? +A: 使用 \`entity.getComponent(YourComponent)\` + +### Q: 如何删除实体? +A: 使用 \`entity.destroy()\` 或 \`this.destroyEntity(entity)\` + +--- + +🎮 **开始您的ECS开发之旅吧!** + +如有问题,请查阅官方文档或提交Issue。 +`); + } + + /** + * 写入文件 + */ + private writeFile(filePath: string, content: string): void { + fs.writeFileSync(filePath, content, 'utf8'); + console.log(`Created file: ${path.relative(this.projectPath, filePath)}`); + } +} diff --git a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/source/main.ts b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/source/main.ts new file mode 100644 index 00000000..48f3b6d4 --- /dev/null +++ b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/source/main.ts @@ -0,0 +1,245 @@ +// @ts-ignore +import packageJSON from '../package.json'; +import { exec } from 'child_process'; +import * as path from 'path'; +import { readFileSync, outputFile } from 'fs-extra'; +import { join } from 'path'; +import { TemplateGenerator } from './TemplateGenerator'; + +/** + * @en Registration method for the main process of Extension + * @zh 为扩展的主进程的注册方法 + */ +export const methods: { [key: string]: (...any: any) => any } = { + /** + * @en A method that can be triggered by message + * @zh 通过 message 触发的方法 + */ + openPanel() { + Editor.Panel.open(packageJSON.name); + }, + + /** + * 安装ECS Framework + */ + 'install-ecs-framework'() { + const projectPath = Editor.Project.path; + const command = 'npm install @esengine/ecs-framework'; + + console.log(`Installing ECS Framework to project: ${projectPath}`); + console.log(`Command: ${command}`); + + exec(command, { cwd: projectPath }, (error, stdout, stderr) => { + console.log('Install stdout:', stdout); + console.log('Install stderr:', stderr); + + if (error) { + console.error('Installation failed:', error); + } else { + console.log('Installation completed successfully'); + + // 验证安装是否成功 + const nodeModulesPath = path.join(projectPath, 'node_modules', '@esengine', 'ecs-framework'); + const installSuccess = require('fs').existsSync(nodeModulesPath); + + if (installSuccess) { + console.log('ECS Framework installed successfully'); + } else { + console.warn('ECS Framework directory not found after install'); + } + } + }); + }, + + /** + * 更新ECS Framework + */ + 'update-ecs-framework'(targetVersion?: string) { + const projectPath = Editor.Project.path; + const version = targetVersion ? `@${targetVersion}` : '@latest'; + const command = `npm install @esengine/ecs-framework${version}`; + + console.log(`Updating ECS Framework to ${version} in project: ${projectPath}`); + console.log(`Command: ${command}`); + + exec(command, { cwd: projectPath }, (error, stdout, stderr) => { + console.log('Update stdout:', stdout); + console.log('Update stderr:', stderr); + + if (error) { + console.error('Update failed:', error); + } else { + console.log('Update completed successfully'); + + // 验证更新是否成功 + const nodeModulesPath = path.join(projectPath, 'node_modules', '@esengine', 'ecs-framework'); + const updateSuccess = require('fs').existsSync(nodeModulesPath); + + if (updateSuccess) { + console.log(`ECS Framework updated successfully to ${version}`); + } else { + console.warn('ECS Framework directory not found after update'); + } + } + }); + }, + + /** + * 卸载ECS Framework + */ + 'uninstall-ecs-framework'() { + const projectPath = Editor.Project.path; + const command = 'npm uninstall @esengine/ecs-framework'; + + console.log(`Uninstalling ECS Framework from project: ${projectPath}`); + console.log(`Command: ${command}`); + + exec(command, { cwd: projectPath }, (error, stdout, stderr) => { + console.log('Uninstall stdout:', stdout); + console.log('Uninstall stderr:', stderr); + + if (error) { + console.error('Uninstall failed:', error); + } else { + console.log('Uninstall completed successfully'); + + // 检查是否真的卸载了 + const nodeModulesPath = path.join(projectPath, 'node_modules', '@esengine', 'ecs-framework'); + const stillExists = require('fs').existsSync(nodeModulesPath); + + if (stillExists) { + console.warn('ECS Framework directory still exists after uninstall'); + } else { + console.log('ECS Framework uninstalled successfully'); + } + } + }); + }, + + /** + * 打开文档 + */ + 'open-documentation'() { + // 使用系统默认命令打开链接 + const url = 'https://github.com/esengine/ecs-framework/blob/master/README.md'; + exec(`start ${url}`, (error) => { + if (error) { + console.error('Failed to open documentation:', error); + Editor.Dialog.info('打开文档', { + detail: `请手动访问以下链接查看文档:\n\n${url}`, + }); + } + }); + }, + + /** + * 创建ECS模板 + */ + 'create-ecs-template'() { + const projectPath = Editor.Project.path; + console.log(`Creating ECS template in project: ${projectPath}`); + + try { + const templateGenerator = new TemplateGenerator(projectPath); + + // 检查是否已存在模板 + if (templateGenerator.checkTemplateExists()) { + const existingFiles = templateGenerator.getExistingFiles(); + const fileList = existingFiles.length > 0 ? existingFiles.join('\n• ') : '未检测到具体文件'; + + Editor.Dialog.warn('模板已存在', { + detail: `检测到已存在ECS模板,包含以下文件:\n\n• ${fileList}\n\n是否要覆盖现有模板?`, + buttons: ['覆盖', '取消'], + }).then((result: any) => { + if (result.response === 0) { + // 用户选择覆盖 + console.log('User chose to overwrite existing template'); + templateGenerator.removeExistingTemplate(); + templateGenerator.createTemplate(); + + Editor.Dialog.info('模板创建成功', { + detail: '✅ ECS项目模板已覆盖并重新创建完成!\n\n已为您的Cocos Creator项目生成了完整的ECS架构模板,包括:\n\n' + + '• 位置、速度、Cocos节点组件\n' + + '• 移动系统和节点同步系统\n' + + '• 实体工厂和场景管理器\n' + + '• ECS管理器组件(可直接添加到节点)\n' + + '• 完整的使用文档\n\n' + + '请刷新资源管理器查看新创建的文件。', + }); + } else { + console.log('User cancelled template creation'); + } + }); + return; + } + + // 创建新模板 + templateGenerator.createTemplate(); + + console.log('ECS template created successfully'); + + Editor.Dialog.info('模板创建成功', { + detail: '✅ ECS项目模板已创建完成!\n\n已为您的Cocos Creator项目生成了完整的ECS架构模板,包括:\n\n' + + '• 位置、速度、Cocos节点组件\n' + + '• 移动系统和节点同步系统\n' + + '• 实体工厂和场景管理器\n' + + '• ECS管理器组件(可直接添加到节点)\n' + + '• 完整的使用文档\n\n' + + '请刷新资源管理器查看新创建的文件。', + }); + + } catch (error) { + console.error('Failed to create ECS template:', error); + const errorMessage = error instanceof Error ? error.message : String(error); + Editor.Dialog.error('模板创建失败', { + detail: `创建ECS模板时发生错误:\n\n${errorMessage}\n\n请检查项目权限和目录结构。`, + }); + } + }, + + /** + * 打开设置 + */ + 'open-settings'() { + Editor.Dialog.info('插件设置', { + detail: '设置面板开发中...\n\n将在下个版本提供完整的插件配置功能。\n\n预计功能:\n• 代码生成模板配置\n• 性能监控设置\n• 自动更新设置\n• 开发工具偏好', + buttons: ['好的'], + }); + }, + + /** + * 项目分析(预留) + */ + 'analyze-project'() { + Editor.Dialog.info('项目分析', { + detail: '项目分析功能开发中...\n\n将在下个版本提供以下分析功能:\n• ECS架构合理性分析\n• 性能瓶颈检测\n• 组件使用统计\n• 系统执行效率分析\n• 内存使用优化建议', + buttons: ['好的'], + }); + }, + + /** + * 组件库(预留) + */ + 'open-component-library'() { + Editor.Dialog.info('组件库', { + detail: '组件库功能开发中...\n\n将在下个版本提供:\n• 常用组件模板库\n• 系统模板库\n• 一键生成组件代码\n• 社区组件分享\n• 组件文档和示例', + buttons: ['好的'], + }); + }, +}; + +/** + * @en Method triggered when the extension is started + * @zh 启动扩展时触发的方法 + */ +export function load() { + console.log('ECS Framework Extension loaded'); +} + +/** + * @en Method triggered when uninstalling the extension + * @zh 卸载扩展时触发的方法 + */ +export function unload() { + console.log('ECS Framework Extension unloaded'); +} diff --git a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/source/panels/default/index.ts b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/source/panels/default/index.ts new file mode 100644 index 00000000..a0948198 --- /dev/null +++ b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/source/panels/default/index.ts @@ -0,0 +1,533 @@ +/* eslint-disable vue/one-component-per-file */ + +import { readFileSync } from 'fs-extra'; +import { join } from 'path'; +import { createApp, App, defineComponent, ref, onMounted } from 'vue'; +import * as fs from 'fs'; +import * as path from 'path'; +import { exec } from 'child_process'; + +const panelDataMap = new WeakMap(); + +/** + * 检测ECS框架安装状态的工具函数 + */ +async function checkEcsFrameworkStatus(projectPath: string) { + const packageJsonPath = path.join(projectPath, 'package.json'); + const nodeModulesPath = path.join(projectPath, 'node_modules', '@esengine', 'ecs-framework'); + + try { + // 检查package.json是否存在 + const packageJsonExists = fs.existsSync(packageJsonPath); + if (!packageJsonExists) { + return { + packageJsonExists: false, + ecsInstalled: false, + ecsVersion: null + }; + } + + // 读取package.json + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')); + + // 检查依赖中是否包含ECS框架 + const dependencies = { ...packageJson.dependencies, ...packageJson.devDependencies }; + const ecsInDeps = dependencies['@esengine/ecs-framework']; + + // 检查node_modules中是否实际安装了ECS框架 + const ecsActuallyInstalled = fs.existsSync(nodeModulesPath); + + let ecsVersion = null; + if (ecsActuallyInstalled) { + try { + const ecsPackageJson = JSON.parse( + fs.readFileSync(path.join(nodeModulesPath, 'package.json'), 'utf-8') + ); + ecsVersion = ecsPackageJson.version; + } catch (e) { + console.warn('Unable to read ECS framework version:', e); + } + } + + return { + packageJsonExists: true, + ecsInstalled: ecsActuallyInstalled && !!ecsInDeps, + ecsVersion, + declaredVersion: ecsInDeps + }; + } catch (error) { + console.error('Error checking ECS framework status:', error); + return { + packageJsonExists: false, + ecsInstalled: false, + ecsVersion: null + }; + } +} + +/** + * 检测ECS模板状态 + */ +function checkEcsTemplateStatus(projectPath: string) { + const ecsDir = path.join(projectPath, 'assets', 'scripts', 'ecs'); + + try { + if (!fs.existsSync(ecsDir)) { + return { + templateExists: false, + existingFiles: [] + }; + } + + // 扫描ECS目录中的文件 + const existingFiles: string[] = []; + function scanDirectory(dirPath: string, relativePath: string = '') { + if (!fs.existsSync(dirPath)) return; + + const items = fs.readdirSync(dirPath); + for (const item of items) { + const fullPath = path.join(dirPath, item); + const relativeFilePath = relativePath ? `${relativePath}/${item}` : item; + + if (fs.statSync(fullPath).isDirectory()) { + scanDirectory(fullPath, relativeFilePath); + } else { + existingFiles.push(relativeFilePath); + } + } + } + + scanDirectory(ecsDir); + + return { + templateExists: existingFiles.length > 0, + existingFiles + }; + } catch (error) { + console.error('Error checking ECS template status:', error); + return { + templateExists: false, + existingFiles: [] + }; + } +} + +/** + * 获取ECS框架的最新版本 + */ +function getLatestEcsVersion(): Promise { + return new Promise((resolve) => { + exec('npm view @esengine/ecs-framework version', (error, stdout) => { + if (error) { + console.warn('Failed to get latest version:', error); + resolve(null); + } else { + resolve(stdout.trim()); + } + }); + }); +} + +/** + * 获取Node.js版本 + */ +function getNodeVersion(): Promise { + return new Promise((resolve) => { + exec('node --version', (error, stdout) => { + if (error) { + resolve('未知'); + } else { + resolve(stdout.trim().replace('v', '')); + } + }); + }); +} + +/** + * 比较版本号 + */ +function compareVersions(current: string, latest: string): boolean { + try { + const currentParts = current.split('.').map(Number); + const latestParts = latest.split('.').map(Number); + + for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) { + const currentPart = currentParts[i] || 0; + const latestPart = latestParts[i] || 0; + + if (latestPart > currentPart) { + return true; // 有更新 + } else if (latestPart < currentPart) { + return false; // 当前版本更新 + } + } + return false; // 版本相同 + } catch (error) { + console.warn('Version comparison failed:', error); + return false; + } +} + +/** + * @zh 如果希望兼容 3.3 之前的版本可以使用下方的代码 + * @en You can add the code below if you want compatibility with versions prior to 3.3 + */ +// Editor.Panel.define = Editor.Panel.define || function(options: any) { return options } + +module.exports = Editor.Panel.define({ + listeners: { + show() { console.log('ECS Welcome Panel Show'); }, + hide() { console.log('ECS Welcome Panel Hide'); }, + }, + template: readFileSync(join(__dirname, '../../../static/template/default/index.html'), 'utf-8'), + style: readFileSync(join(__dirname, '../../../static/style/default/index.css'), 'utf-8'), + $: { + app: '#app', + }, + methods: { + /** + * 向主进程发送消息的方法 + */ + sendToMain(message: string, ...args: any[]) { + Editor.Message.send('cocos-ecs-extension', message, ...args); + } + }, + ready() { + if (this.$.app) { + const app = createApp({}); + app.config.compilerOptions.isCustomElement = (tag) => tag.startsWith('ui-'); + + // ECS欢迎组件 + app.component('EcsWelcome', defineComponent({ + setup() { + // 响应式状态 + const checkingStatus = ref(true); + const ecsInstalled = ref(false); + const ecsVersion = ref(null); + const latestVersion = ref(null); + const hasUpdate = ref(false); + const packageJsonExists = ref(false); + const nodeVersion = ref('检测中...'); + const pluginVersion = ref('1.0.0'); + const lastCheckTime = ref(null); + + // ECS模板状态 + const templateExists = ref(false); + const existingFiles = ref([]); + + // 操作状态 + const installing = ref(false); + const updating = ref(false); + const uninstalling = ref(false); + + // 操作状态显示 + const showOperationStatus = ref(false); + const operationStatusType = ref('loading'); + const operationStatusMessage = ref(''); + const operationStatusDetails = ref(''); + + // 显示操作状态 + const setOperationStatus = (type: string, message: string, details?: string) => { + showOperationStatus.value = true; + operationStatusType.value = type; + operationStatusMessage.value = message; + operationStatusDetails.value = details || ''; + + // 自动隐藏成功和警告消息 + if (type === 'success' || type === 'warning') { + setTimeout(() => { + showOperationStatus.value = false; + }, 5000); + } + }; + + // 获取状态图标 + const getStatusIcon = (type: string) => { + switch (type) { + case 'loading': return '⏳'; + case 'success': return '✅'; + case 'error': + case 'failed': return '❌'; + case 'warning': return '⚠️'; + default: return 'ℹ️'; + } + }; + + // 监听来自主进程的消息 - 暂时注释掉,使用定时刷新 + const setupMessageListeners = () => { + // TODO: 使用正确的消息监听API + console.log('Message listeners setup - using polling instead'); + }; + + // 定时检查状态(用于检测操作完成) + let statusCheckInterval: any = null; + const startStatusPolling = () => { + if (statusCheckInterval) clearInterval(statusCheckInterval); + statusCheckInterval = setInterval(() => { + if (installing.value || updating.value || uninstalling.value) { + checkStatus(); + } + }, 3000); // 每3秒检查一次 + }; + + const stopStatusPolling = () => { + if (statusCheckInterval) { + clearInterval(statusCheckInterval); + statusCheckInterval = null; + } + }; + + // 检测状态的方法 + const checkStatus = async () => { + checkingStatus.value = true; + + try { + // 获取当前项目路径 + const projectPath = Editor.Project.path; + + // 检测ECS框架状态 + const status = await checkEcsFrameworkStatus(projectPath); + const prevInstalled = ecsInstalled.value; + const prevVersion = ecsVersion.value; + + packageJsonExists.value = status.packageJsonExists; + ecsInstalled.value = status.ecsInstalled; + ecsVersion.value = status.ecsVersion; + + // 检测ECS模板状态 + const templateStatus = checkEcsTemplateStatus(projectPath); + templateExists.value = templateStatus.templateExists; + existingFiles.value = templateStatus.existingFiles; + + // 检测操作完成 + if (installing.value) { + if (status.ecsInstalled && !prevInstalled) { + installing.value = false; + setOperationStatus('success', 'ECS Framework 安装成功!'); + stopStatusPolling(); + } else if (!status.ecsInstalled) { + // 可能还在安装中,继续等待 + } + } + + if (updating.value) { + if (status.ecsVersion && status.ecsVersion !== prevVersion) { + updating.value = false; + setOperationStatus('success', `ECS Framework 更新成功到 v${status.ecsVersion}!`); + stopStatusPolling(); + } + } + + if (uninstalling.value) { + if (!status.ecsInstalled && prevInstalled) { + uninstalling.value = false; + setOperationStatus('success', 'ECS Framework 卸载成功!'); + stopStatusPolling(); + } + } + + // 获取Node.js版本 + nodeVersion.value = await getNodeVersion(); + + // 检查更新 + if (ecsInstalled.value && ecsVersion.value) { + await checkForUpdates(); + } + + // 更新检查时间 + lastCheckTime.value = new Date().toLocaleString(); + + } catch (error) { + console.error('Status check failed:', error); + + // 如果检查失败,停止操作状态 + if (installing.value || updating.value || uninstalling.value) { + installing.value = false; + updating.value = false; + uninstalling.value = false; + setOperationStatus('error', '状态检查失败,请手动验证操作结果'); + stopStatusPolling(); + } + } finally { + checkingStatus.value = false; + } + }; + + // 检查更新 + const checkForUpdates = async () => { + if (!ecsInstalled.value || !ecsVersion.value) { + setOperationStatus('warning', '请先安装 ECS Framework'); + return; + } + + try { + setOperationStatus('loading', '正在检查更新...'); + + const latest = await getLatestEcsVersion(); + if (latest) { + latestVersion.value = latest; + const needsUpdate = compareVersions(ecsVersion.value, latest); + hasUpdate.value = needsUpdate; + + if (needsUpdate) { + setOperationStatus('success', `发现新版本:v${latest}(当前:v${ecsVersion.value})`); + } else { + setOperationStatus('success', `已是最新版本:v${ecsVersion.value}`); + } + } else { + setOperationStatus('warning', '无法获取最新版本信息,请检查网络连接'); + } + + // 更新检查时间 + lastCheckTime.value = new Date().toLocaleString(); + + } catch (error) { + console.warn('Failed to check updates:', error); + setOperationStatus('error', '检查更新失败,请检查网络连接'); + } + }; + + // 操作方法 + const installEcsFramework = () => { + if (!packageJsonExists.value || installing.value) return; + + Editor.Dialog.info('安装 ECS Framework', { + detail: '即将安装@esengine/ecs-framework到当前项目...', + buttons: ['确定', '取消'], + default: 0, + }).then((result) => { + if (result.response === 0) { + installing.value = true; + setOperationStatus('loading', '正在安装 ECS Framework...'); + startStatusPolling(); + + // 发送安装命令到主进程 + Editor.Message.send('cocos-ecs-extension', 'install-ecs-framework'); + } + }); + }; + + const updateEcsFramework = () => { + if (!hasUpdate.value || updating.value) return; + + Editor.Dialog.info('更新 ECS Framework', { + detail: `即将更新ECS框架从 v${ecsVersion.value} 到 v${latestVersion.value}`, + buttons: ['确定', '取消'], + default: 0, + }).then((result) => { + if (result.response === 0) { + updating.value = true; + setOperationStatus('loading', `正在更新 ECS Framework 到 v${latestVersion.value}...`); + startStatusPolling(); + + Editor.Message.send('cocos-ecs-extension', 'update-ecs-framework', latestVersion.value); + } + }); + }; + + const uninstallEcsFramework = () => { + if (uninstalling.value) return; + + Editor.Dialog.warn('卸载 ECS Framework', { + detail: '确定要卸载ECS框架吗?这将删除项目中的ECS框架依赖。', + buttons: ['确定卸载', '取消'], + default: 1, + }).then((result) => { + if (result.response === 0) { + uninstalling.value = true; + setOperationStatus('loading', '正在卸载 ECS Framework...'); + startStatusPolling(); + + Editor.Message.send('cocos-ecs-extension', 'uninstall-ecs-framework'); + } + }); + }; + + const openDocumentation = () => { + if (!ecsInstalled.value) return; + Editor.Message.send('cocos-ecs-extension', 'open-documentation'); + }; + + const createEcsTemplate = () => { + if (!ecsInstalled.value || templateExists.value) return; + + Editor.Dialog.info('创建 ECS 模板', { + detail: '即将创建基础的ECS项目结构和启动代码...', + buttons: ['确定', '取消'], + default: 0, + }).then((result) => { + if (result.response === 0) { + Editor.Message.send('cocos-ecs-extension', 'create-ecs-template'); + } + }); + }; + + const openSettings = () => { + Editor.Message.send('cocos-ecs-extension', 'open-settings'); + }; + + const openProjectAnalysis = () => { + Editor.Message.send('cocos-ecs-extension', 'open-project-analysis'); + }; + + const openComponentLibrary = () => { + Editor.Message.send('cocos-ecs-extension', 'open-component-library'); + }; + + const openGithub = () => { + Editor.Message.send('cocos-ecs-extension', 'open-github'); + }; + + // 组件挂载后检测状态 + onMounted(() => { + setupMessageListeners(); + checkStatus(); + }); + + return { + checkingStatus, + ecsInstalled, + ecsVersion, + latestVersion, + hasUpdate, + packageJsonExists, + nodeVersion, + pluginVersion, + lastCheckTime, + templateExists, + existingFiles, + installing, + updating, + uninstalling, + showOperationStatus, + operationStatusType, + operationStatusMessage, + operationStatusDetails, + getStatusIcon, + installEcsFramework, + updateEcsFramework, + uninstallEcsFramework, + checkForUpdates, + openDocumentation, + createEcsTemplate, + openSettings, + openProjectAnalysis, + openComponentLibrary, + openGithub + }; + }, + template: readFileSync(join(__dirname, '../../../static/template/vue/welcome.html'), 'utf-8'), + })); + + app.mount(this.$.app); + panelDataMap.set(this, app); + } + }, + beforeClose() { }, + close() { + const app = panelDataMap.get(this); + if (app) { + app.unmount(); + } + }, +}); diff --git a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/style/default/index.css b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/style/default/index.css new file mode 100644 index 00000000..1580bdcb --- /dev/null +++ b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/style/default/index.css @@ -0,0 +1,450 @@ +#text { + color: var(--color-normal-contrast-weakest); + margin: auto; + width: 180px; +} +.counter { + text-align: center; +} + +.ecs-welcome-panel { + height: 100%; + background: var(--color-panel-bg); + color: var(--color-text-normal); + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + overflow: hidden; +} + +.welcome-container { + padding: 16px; + height: 100%; + display: flex; + flex-direction: column; + overflow-y: auto; + overflow-x: hidden; + max-height: 100vh; + box-sizing: border-box; +} + +.header { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + padding: 16px; + border-radius: 6px; + margin-bottom: 16px; + text-align: center; + flex-shrink: 0; +} + +.header h1 { + margin: 0 0 6px 0; + font-size: 20px; + font-weight: 600; +} + +.header p { + margin: 0; + opacity: 0.9; + font-size: 13px; +} + +.status-section { + background: var(--color-area-bg); + border: 1px solid var(--color-border); + border-radius: 6px; + padding: 14px; + margin-bottom: 14px; + flex-shrink: 0; +} + +.status-title { + font-size: 15px; + font-weight: 600; + margin-bottom: 10px; + color: var(--color-text-normal); +} + +.status-item { + display: flex; + align-items: center; + justify-content: space-between; + padding: 8px 0; + border-bottom: 1px solid var(--color-border-soft); + flex-wrap: wrap; + gap: 8px; +} + +.status-item:last-child { + border-bottom: none; +} + +.status-label { + color: var(--color-text-contrast-weakest); + flex: 1; + min-width: 200px; +} + +.status-badge { + padding: 4px 8px; + border-radius: 4px; + font-size: 12px; + font-weight: 500; + white-space: nowrap; +} + +.status-badge.installed { + background: #d4edda; + color: #155724; + border: 1px solid #c3e6cb; +} + +.status-badge.not-installed { + background: #f8d7da; + color: #721c24; + border: 1px solid #f5c6cb; +} + +.status-badge.checking { + background: #fff3cd; + color: #856404; + border: 1px solid #ffeaa7; +} + +.version-info { + font-family: 'Courier New', monospace; + font-size: 11px; + color: var(--color-text-contrast-weak); +} + +.update-hint { + color: #ff6b35; + font-size: 10px; + font-weight: 600; + margin-left: 8px; + display: block; + margin-top: 2px; +} + +.management-buttons { + display: flex; + flex-direction: column; + gap: 8px; + margin-top: 8px; +} + +.management-buttons ui-button { + width: 100%; + min-height: 32px; + font-size: 12px; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + padding: 8px 12px; +} + +.management-buttons ui-button:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.management-buttons ui-button.green { + background-color: #28a745; + color: white; + border: 1px solid #28a745; +} + +.management-buttons ui-button.red { + background-color: #dc3545; + color: white; + border: 1px solid #dc3545; +} + +.management-buttons ui-button.blue { + background-color: #007bff; + color: white; + border: 1px solid #007bff; +} + +.operation-status { + padding: 12px; + border-radius: 6px; + margin-top: 8px; +} + +.operation-status.loading { + background: #fff3cd; + border: 1px solid #ffeaa7; + color: #856404; +} + +.operation-status.success { + background: #d4edda; + border: 1px solid #c3e6cb; + color: #155724; +} + +.operation-status.error, +.operation-status.failed { + background: #f8d7da; + border: 1px solid #f5c6cb; + color: #721c24; +} + +.operation-status.warning { + background: #fff3cd; + border: 1px solid #ffeaa7; + color: #856404; +} + +.status-content { + display: flex; + align-items: center; + gap: 8px; +} + +.status-icon { + font-size: 16px; +} + +.status-text { + flex: 1; + font-weight: 500; +} + +.status-details { + margin-top: 8px; + font-size: 11px; + opacity: 0.8; + white-space: pre-line; +} + +.actions-section { + background: var(--color-area-bg); + border: 1px solid var(--color-border); + border-radius: 6px; + padding: 14px; + margin-bottom: 14px; + flex-shrink: 0; +} + +.action-card { + background: var(--color-neutral-bg); + border: 1px solid var(--color-border); + border-radius: 6px; + padding: 12px; + margin-bottom: 10px; + cursor: pointer; + transition: all 0.2s ease; +} + +.action-card:last-child { + margin-bottom: 0; +} + +.action-card h3 { + margin: 0 0 6px 0; + font-size: 14px; + font-weight: 600; + color: var(--color-text-normal); + display: flex; + align-items: center; + gap: 8px; +} + +.action-card p { + margin: 0; + font-size: 12px; + color: var(--color-text-contrast-weakest); + line-height: 1.4; +} + +.footer { + background: var(--color-area-bg); + border: 1px solid var(--color-border); + border-radius: 6px; + padding: 12px; + margin-top: 8px; + text-align: center; + font-size: 11px; + color: var(--color-text-contrast-weak); + flex-shrink: 0; +} + +.footer a { + color: var(--color-primary); + text-decoration: none; +} + +.footer a:hover { + text-decoration: underline; +} + +.last-check { + margin-top: 4px; + font-size: 10px; + opacity: 0.7; +} + +.loading-spinner { + display: inline-block; + width: 14px; + height: 14px; + border: 2px solid var(--color-border); + border-top: 2px solid var(--color-primary); + border-radius: 50%; + animation: spin 1s linear infinite; + margin-right: 6px; + vertical-align: middle; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +.icon { + margin-right: 8px; + font-size: 16px; +} + +/* 优化滚动条样式 */ +.welcome-container::-webkit-scrollbar { + width: 8px; +} + +.welcome-container::-webkit-scrollbar-track { + background: var(--color-area-bg); + border-radius: 4px; +} + +.welcome-container::-webkit-scrollbar-thumb { + background: var(--color-border-emphasis); + border-radius: 4px; + opacity: 0.5; +} + +.welcome-container::-webkit-scrollbar-thumb:hover { + background: var(--color-border-emphasis-strong); + opacity: 0.8; +} + +/* 状态切换动画 */ +.status-badge { + transition: all 0.3s ease; +} + +.action-card { + transform: translateY(0); + transition: all 0.2s ease; +} + +.action-card:hover:not(.disabled) { + background: var(--color-area-bg-hover); + border-color: var(--color-primary-highlight); + transform: translateY(-1px); +} + +.action-card.disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.action-card.disabled:hover { + background: var(--color-neutral-bg); + border-color: var(--color-border); + transform: none; +} + +/* 响应式布局优化 */ +@media (max-width: 600px) { + .welcome-container { + padding: 16px; + } + + .header h1 { + font-size: 20px; + } + + .status-item { + flex-direction: column; + align-items: flex-start; + } + + .status-label { + min-width: auto; + margin-bottom: 4px; + } +} + +/* 确保按钮文本不被截断 */ +.management-buttons ui-button { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +/* 现有文件信息样式 */ +.existing-files-info { + margin-top: 12px; + padding: 10px; + background: var(--color-area-bg); + border: 1px solid var(--color-border); + border-radius: 4px; + font-size: 11px; +} + +.files-summary { + font-weight: 600; + color: var(--color-text-normal); + margin-bottom: 8px; + padding-bottom: 6px; + border-bottom: 1px solid var(--color-border); +} + +.files-list, +.files-overflow { + max-height: 120px; + overflow-y: auto; +} + +.file-item { + padding: 2px 0; + color: var(--color-text-contrast-weak); + font-family: var(--font-mono); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.more-files { + padding: 4px 0; + color: var(--color-text-contrast-weakest); + font-style: italic; + border-top: 1px solid var(--color-border); + margin-top: 4px; + padding-top: 6px; +} + +/* 文件列表滚动条样式 */ +.files-list::-webkit-scrollbar, +.files-overflow::-webkit-scrollbar { + width: 6px; +} + +.files-list::-webkit-scrollbar-track, +.files-overflow::-webkit-scrollbar-track { + background: var(--color-area-bg); + border-radius: 3px; +} + +.files-list::-webkit-scrollbar-thumb, +.files-overflow::-webkit-scrollbar-thumb { + background: var(--color-border); + border-radius: 3px; +} + +.files-list::-webkit-scrollbar-thumb:hover, +.files-overflow::-webkit-scrollbar-thumb:hover { + background: var(--color-border-emphasis); +} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/template/default/index.html b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/template/default/index.html new file mode 100644 index 00000000..77446564 --- /dev/null +++ b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/template/default/index.html @@ -0,0 +1,5 @@ +
+
+ +
+
\ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/template/vue/counter.html b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/template/vue/counter.html new file mode 100644 index 00000000..eee34498 --- /dev/null +++ b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/template/vue/counter.html @@ -0,0 +1,6 @@ +
+

{{counter}}

+ + + - +
\ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/template/vue/welcome.html b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/template/vue/welcome.html new file mode 100644 index 00000000..8f6db2e7 --- /dev/null +++ b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/template/vue/welcome.html @@ -0,0 +1,169 @@ +
+ +
+

🎮 ECS Framework for Cocos Creator

+

高性能实体组件系统框架

+
+ + +
+
📋 操作状态
+
+
+ + {{ getStatusIcon(operationStatusType) }} + {{ operationStatusMessage }} +
+
+ {{ operationStatusDetails }} +
+
+
+ + +
+
📦 安装状态检测
+ +
+ ECS Framework (@esengine/ecs-framework) +
+ 检测中... +
+
+ ✅ 已安装 v{{ecsVersion}} + 有新版本:v{{latestVersion}} +
+
+ ❌ 未安装 +
+
+ +
+ 项目package.json +
+ ✅ 存在 +
+
+ ❌ 不存在 +
+
+ +
+ Node.js环境 +
+ ✅ v{{nodeVersion}} +
+
+
+ + +
+
🔧 ECS Framework 管理
+ +
+ + + {{ updating ? '更新中...' : (hasUpdate ? `更新到 v${latestVersion}` : '已是最新版本') }} + + + + + {{ uninstalling ? '卸载中...' : '卸载 ECS Framework' }} + + + + 🔄 检查更新 + +
+
+ + +
+
🚀 快速开始
+ +
+

+ 📥 + {{ ecsInstalled ? '重新安装 ECS Framework' : '安装 ECS Framework' }} +

+

正在安装中,请稍候...

+

请先确保项目有package.json文件

+

重新安装当前版本的ECS框架

+

安装@esengine/ecs-framework到当前项目

+
+ +
+

+ 📚 + 查看文档 +

+

打开ECS框架完整使用文档和教程

+
+ +
+

+ 🛠️ + 创建ECS模板 +

+

请先安装 ECS Framework

+

⚠️ ECS模板已存在,避免覆盖现有代码

+

生成基础的ECS项目结构和启动代码

+ +
+
+ 检测到 {{existingFiles.length}} 个已存在的文件 +
+
+
+ 📄 {{file}} +
+
+
+
+ 📄 {{file}} +
+
... 还有 {{existingFiles.length - 8}} 个文件
+
+
+
+ +
+

+ ⚙️ + 插件设置 +

+

配置ECS插件的各项设置和偏好

+
+ +
+

+ 📊 + 项目分析 +

+

分析当前项目的ECS使用情况和性能建议

+
+ +
+

+ 🧩 + 组件库 +

+

浏览和管理项目中的ECS组件

+
+
+ + + +
\ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/tsconfig.json b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/tsconfig.json new file mode 100644 index 00000000..78832ecd --- /dev/null +++ b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "./base.tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./source", + "types": [ + "node", + "@cocos/creator-types/editor", + ] + } +} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/package-lock.json b/extensions/cocos/cocos-ecs/package-lock.json new file mode 100644 index 00000000..86d3844b --- /dev/null +++ b/extensions/cocos/cocos-ecs/package-lock.json @@ -0,0 +1,21 @@ +{ + "name": "cocos-ecs", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "cocos-ecs", + "dependencies": { + "@esengine/ecs-framework": "^2.1.19" + } + }, + "node_modules/@esengine/ecs-framework": { + "version": "2.1.19", + "resolved": "https://registry.npmjs.org/@esengine/ecs-framework/-/ecs-framework-2.1.19.tgz", + "integrity": "sha512-yS6g1Swdd/FvnIrdmaxBh6ml5r+Oh4edIhGwVfEbzQMHUmrZQbva7/NGyOhTsJ6qsIGVyNin8o46tTud2YCj4g==", + "engines": { + "node": ">=16.0.0" + } + } + } +} diff --git a/extensions/cocos/cocos-ecs/package.json b/extensions/cocos/cocos-ecs/package.json new file mode 100644 index 00000000..5e026a30 --- /dev/null +++ b/extensions/cocos/cocos-ecs/package.json @@ -0,0 +1,10 @@ +{ + "name": "cocos-ecs", + "uuid": "e17e4eb7-dfe2-4f87-b77d-13c36da216e3", + "creator": { + "version": "3.8.6" + }, + "dependencies": { + "@esengine/ecs-framework": "^2.1.19" + } +} diff --git a/extensions/cocos/cocos-ecs/settings/v2/packages/builder.json b/extensions/cocos/cocos-ecs/settings/v2/packages/builder.json new file mode 100644 index 00000000..7526e407 --- /dev/null +++ b/extensions/cocos/cocos-ecs/settings/v2/packages/builder.json @@ -0,0 +1,3 @@ +{ + "__version__": "1.3.9" +} diff --git a/extensions/cocos/cocos-ecs/settings/v2/packages/device.json b/extensions/cocos/cocos-ecs/settings/v2/packages/device.json new file mode 100644 index 00000000..70e599e6 --- /dev/null +++ b/extensions/cocos/cocos-ecs/settings/v2/packages/device.json @@ -0,0 +1,3 @@ +{ + "__version__": "1.0.1" +} diff --git a/extensions/cocos/cocos-ecs/settings/v2/packages/engine.json b/extensions/cocos/cocos-ecs/settings/v2/packages/engine.json new file mode 100644 index 00000000..d3eab472 --- /dev/null +++ b/extensions/cocos/cocos-ecs/settings/v2/packages/engine.json @@ -0,0 +1,3 @@ +{ + "__version__": "1.0.12" +} diff --git a/extensions/cocos/cocos-ecs/settings/v2/packages/information.json b/extensions/cocos/cocos-ecs/settings/v2/packages/information.json new file mode 100644 index 00000000..94848dec --- /dev/null +++ b/extensions/cocos/cocos-ecs/settings/v2/packages/information.json @@ -0,0 +1,23 @@ +{ + "__version__": "1.0.1", + "information": { + "customSplash": { + "id": "customSplash", + "label": "customSplash", + "enable": false, + "customSplash": { + "complete": false, + "form": "https://creator-api.cocos.com/api/form/show?" + } + }, + "removeSplash": { + "id": "removeSplash", + "label": "removeSplash", + "enable": false, + "removeSplash": { + "complete": false, + "form": "https://creator-api.cocos.com/api/form/show?" + } + } + } +} diff --git a/extensions/cocos/cocos-ecs/settings/v2/packages/program.json b/extensions/cocos/cocos-ecs/settings/v2/packages/program.json new file mode 100644 index 00000000..916c1b20 --- /dev/null +++ b/extensions/cocos/cocos-ecs/settings/v2/packages/program.json @@ -0,0 +1,3 @@ +{ + "__version__": "1.0.4" +} diff --git a/extensions/cocos/cocos-ecs/settings/v2/packages/project.json b/extensions/cocos/cocos-ecs/settings/v2/packages/project.json new file mode 100644 index 00000000..4129dde8 --- /dev/null +++ b/extensions/cocos/cocos-ecs/settings/v2/packages/project.json @@ -0,0 +1,3 @@ +{ + "__version__": "1.0.6" +} diff --git a/extensions/cocos/cocos-ecs/tsconfig.json b/extensions/cocos/cocos-ecs/tsconfig.json new file mode 100644 index 00000000..7dc649a9 --- /dev/null +++ b/extensions/cocos/cocos-ecs/tsconfig.json @@ -0,0 +1,9 @@ +{ + /* Base configuration. Do not edit this field. */ + "extends": "./temp/tsconfig.cocos.json", + + /* Add your custom configuration here. */ + "compilerOptions": { + "strict": false + } +}