fix: 修复一系列 bug
This commit is contained in:
@@ -4,6 +4,7 @@ import { ViewManager } from './scripts/core/ViewManager';
|
||||
import { LevelDataManager } from './scripts/utils/LevelDataManager';
|
||||
import { AuthManager } from './scripts/utils/AuthManager';
|
||||
import { ShareManager } from './scripts/utils/ShareManager';
|
||||
import { ShareLaunchHandler } from './scripts/utils/ShareLaunchHandler';
|
||||
import { WxSDK } from './scripts/utils/WxSDK';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@@ -92,6 +93,9 @@ export class PageLoading extends Component {
|
||||
this._updateStatusLabel('正在加载挑战关卡...');
|
||||
const joinSuccess = await ShareManager.instance.joinShare(shareCode);
|
||||
if (joinSuccess) {
|
||||
// 把启动 shareCode 同步给 ShareLaunchHandler,
|
||||
// 避免 wx.onShow 在初始展示时拿到同一个 code 又走一遍 join。
|
||||
ShareLaunchHandler.instance.markActiveShareCode(shareCode);
|
||||
this._updateProgress(1);
|
||||
this._updateStatusLabel('加载完成');
|
||||
// 跳过首页,直接进入分享挑战关卡
|
||||
@@ -134,6 +138,20 @@ export class PageLoading extends Component {
|
||||
this._updateProgress(1);
|
||||
this._updateStatusLabel('加载完成');
|
||||
|
||||
// 兜底:如果在 PageLoading 还在 preload 期间,wx.onShow 已经把游戏切到了分享态
|
||||
// (ShareLaunchHandler 已经 joinShare 成功),这里就不应再覆盖回首页,
|
||||
// 否则用户点了好友分享卡片却看到 PageHome。
|
||||
if (ShareManager.instance.isShareMode) {
|
||||
console.log('[PageLoading] 检测到分享态已激活,跳过首页直达 PageLevel');
|
||||
ViewManager.instance.open('PageLevel', {
|
||||
params: { shareMode: true },
|
||||
onComplete: () => {
|
||||
this.node.destroy();
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
ViewManager.instance.open('PageHome', {
|
||||
onComplete: () => {
|
||||
this.node.destroy();
|
||||
|
||||
@@ -2,6 +2,7 @@ import { _decorator, Component, Prefab, AudioClip } from 'cc';
|
||||
import { ViewManager } from './scripts/core/ViewManager';
|
||||
import { ToastManager } from './scripts/utils/ToastManager';
|
||||
import { AudioManager } from './scripts/utils/AudioManager';
|
||||
import { ShareLaunchHandler } from './scripts/utils/ShareLaunchHandler';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/**
|
||||
@@ -115,5 +116,10 @@ export class main extends Component {
|
||||
}
|
||||
|
||||
AudioManager.instance.init(this.buttonClickAudio, this.node);
|
||||
|
||||
// 注册 wx.onShow / wx.onHide:
|
||||
// 用户把小游戏退到后台后再点击好友分享卡片,能拿到最新的 shareCode 并直达分享挑战关卡。
|
||||
// 必须在 PageLoading 跑之前注册,这样初始 launch 中的 shareCode 也会被作为种子记下。
|
||||
ShareLaunchHandler.instance.init();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5507,7 +5507,7 @@
|
||||
"b": 0,
|
||||
"a": 255
|
||||
},
|
||||
"_string": "还差3题获得冷场小白2级",
|
||||
"_string": "还差3题,解锁新成就等级",
|
||||
"_horizontalAlign": 1,
|
||||
"_verticalAlign": 1,
|
||||
"_actualFontSize": 40,
|
||||
|
||||
@@ -61,7 +61,7 @@ export class PageHome extends BaseView {
|
||||
/** 是否正在播放体力消耗动画 */
|
||||
private _isAnimating: boolean = false;
|
||||
|
||||
/** 进度游标 0% 时的本地 X 坐标,使用 prefab 当前摆放位置作为起点 */
|
||||
/** 进度游标 0% 时的本地 X 坐标,根据 ProgressBar Bar 子节点的左端推导出来 */
|
||||
private _progressAnchorStartX: number | null = null;
|
||||
|
||||
/**
|
||||
@@ -363,11 +363,23 @@ export class PageHome extends BaseView {
|
||||
}
|
||||
|
||||
private _cacheProgressAnchorStartX(): void {
|
||||
if (this._progressAnchorStartX !== null || !this.progressAnchor) {
|
||||
if (this._progressAnchorStartX !== null || !this.titleProgressBar) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._progressAnchorStartX = this.progressAnchor.position.x;
|
||||
const barSprite = this.titleProgressBar.barSprite;
|
||||
if (!barSprite) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Bar 节点 anchor 为 (0, 0.5),其本地 position.x 即为进度条可视左端。
|
||||
// ProgressBar 与 ProgressAnchor 共享同一父节点(TitleLevel),
|
||||
// 因此把 Bar 的本地 X 按 ProgressBar 自身的位移与缩放映射到父节点空间,
|
||||
// 才是真正的「0% 起点」。直接拿 progressAnchor.position.x 当起点会导致
|
||||
// 气泡始终被 prefab 摆放偏移量带跑(实测偏右 ~24px)。
|
||||
const progressBarNode = this.titleProgressBar.node;
|
||||
const barLocalX = barSprite.node.position.x;
|
||||
this._progressAnchorStartX = progressBarNode.position.x + barLocalX * progressBarNode.scale.x - 30;
|
||||
}
|
||||
|
||||
private _updateProgressAnchor(progress: number): void {
|
||||
|
||||
@@ -292,6 +292,14 @@ export class PageLevel extends BaseView {
|
||||
/** 是否处于分享挑战模式 */
|
||||
private _isShareMode: boolean = false;
|
||||
|
||||
/**
|
||||
* 当前 PageLevel 实例所处分享挑战的 shareCode 缓存。
|
||||
* PageLevel 注册时 cache: true,复用同一个实例。
|
||||
* 当用户在后台切换好友分享卡片时,ShareManager.shareCode 会发生变化,
|
||||
* onViewShow 通过对比这个值与最新的 ShareManager.shareCode 来判断是否需要 _reinitLevelSession。
|
||||
*/
|
||||
private _activeShareCode: string | null = null;
|
||||
|
||||
/** 体力恢复倒计时定时器 */
|
||||
private _staminaTimerId: ReturnType<typeof setInterval> | null = null;
|
||||
|
||||
@@ -335,8 +343,10 @@ export class PageLevel extends BaseView {
|
||||
this._shareSubmissions.clear();
|
||||
this._isSubmittingShareResult = false;
|
||||
this._hasRequestedShareUserInfo = false;
|
||||
this._activeShareCode = ShareManager.instance.shareCode;
|
||||
console.log('[PageLevel] 进入分享挑战模式');
|
||||
} else {
|
||||
this._activeShareCode = null;
|
||||
// 从 AuthManager 获取首关数据(由 PageLoading → game-data 提供)
|
||||
const nextLevel = AuthManager.instance.nextLevel;
|
||||
if (nextLevel) {
|
||||
@@ -373,12 +383,41 @@ export class PageLevel extends BaseView {
|
||||
const params = this.getParams();
|
||||
const desiredShareMode = params?.shareMode === true;
|
||||
|
||||
if (desiredShareMode !== this._isShareMode) {
|
||||
console.log(`[PageLevel] 检测到模式切换 ${this._isShareMode} → ${desiredShareMode},重新初始化关卡会话`);
|
||||
// 当前 ShareManager 中的 shareCode(可能因为后台切到新的分享卡片而变化)
|
||||
const latestShareCode = ShareManager.instance.shareCode;
|
||||
|
||||
const modeChanged = desiredShareMode !== this._isShareMode;
|
||||
// 同样是分享模式,但 ShareManager 中的 shareCode 已经换了一份题单 —— 也必须重建会话
|
||||
const shareCodeChanged = desiredShareMode && latestShareCode !== this._activeShareCode;
|
||||
|
||||
if (modeChanged || shareCodeChanged) {
|
||||
console.log(
|
||||
`[PageLevel] 检测到模式/分享码切换 mode:${this._isShareMode}->${desiredShareMode} ` +
|
||||
`code:${this._activeShareCode}->${latestShareCode},重新初始化关卡会话`,
|
||||
);
|
||||
this._reinitLevelSession(desiredShareMode);
|
||||
return;
|
||||
}
|
||||
|
||||
// 上一次离场时如果停留在「答对后通关流程」(_isTransitioning=true 由 showSuccess 置位、
|
||||
// 而 _applyLevelConfig 才会重置),缓存的 PageLevel 实例会保留完成态:
|
||||
// - 输入格已填入正确答案
|
||||
// - 提交按钮被 _isTransitioning 锁住,无法重新提交
|
||||
// - 倒计时已停、谐音梗已揭示
|
||||
// 此时玩家从首页再次进入会看到一个无法操作的"死局"。必须把会话推进到下一关。
|
||||
// 注意:这只可能在主线模式发生 —— 分享模式下点 iconSetting / PassModal 的 home
|
||||
// 都会调用 ShareManager.clearShareMode + ViewManager.replace,再次进入会被
|
||||
// 上面的 modeChanged / shareCodeChanged 分支拦截走 _reinitLevelSession。
|
||||
if (this._isTransitioning) {
|
||||
console.log('[PageLevel] 上次离场时停留在通关后状态,自动推进到下一关');
|
||||
this._closePassModal();
|
||||
this._closeWrongModal();
|
||||
this._closeTimeoutModal();
|
||||
this._closeCommonModal();
|
||||
void this.goToNextLevel();
|
||||
return;
|
||||
}
|
||||
|
||||
this._refreshModeUI();
|
||||
this.updateStaminaLabel();
|
||||
if (!this._isShareMode) {
|
||||
@@ -408,8 +447,10 @@ export class PageLevel extends BaseView {
|
||||
this._hasRequestedShareUserInfo = false;
|
||||
|
||||
if (this._isShareMode) {
|
||||
console.log('[PageLevel] 切换到分享挑战模式');
|
||||
this._activeShareCode = ShareManager.instance.shareCode;
|
||||
console.log(`[PageLevel] 切换到分享挑战模式 (shareCode=${this._activeShareCode})`);
|
||||
} else {
|
||||
this._activeShareCode = null;
|
||||
// 主线模式:从 AuthManager 拉取最新的 nextLevel
|
||||
this._nextLevelData = null;
|
||||
const nextLevel = AuthManager.instance.nextLevel;
|
||||
@@ -866,6 +907,16 @@ export class PageLevel extends BaseView {
|
||||
console.log('[PageLevel] IconSetting 点击,返回主页');
|
||||
AudioManager.instance.playButtonClick();
|
||||
|
||||
// 离开 PageLevel 时把所有挂在 Canvas 上的关卡级弹窗一起清掉。
|
||||
// PassModal / WrongModal / TimeoutModal / CommonModal 都是 addChild 到 this.node.parent
|
||||
// 也就是 PageLevel 的兄弟节点,PageLevel 被 ViewManager 隐藏后它们并不会自动消失,
|
||||
// 否则会孤儿地盖在 PageHome 上。同时清掉 PassModal 也避免再次进入时缓存实例
|
||||
// 残留 _passModalNode 引用让 _swapToNextLevelImagesIfReady 误判弹窗仍在打开。
|
||||
this._closePassModal();
|
||||
this._closeWrongModal();
|
||||
this._closeTimeoutModal();
|
||||
this._closeCommonModal();
|
||||
|
||||
// 分享模式下栈中没有 PageHome,需要清除分享状态并直接打开首页
|
||||
if (this._isShareMode) {
|
||||
ShareManager.instance.clearShareMode();
|
||||
|
||||
@@ -244,7 +244,7 @@
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_active": false,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 11
|
||||
@@ -426,7 +426,7 @@
|
||||
"__id__": 25
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_active": false,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 71
|
||||
@@ -2106,8 +2106,8 @@
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -172.179,
|
||||
"y": -613.418,
|
||||
"x": -142.654,
|
||||
"y": 760.825,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -2147,7 +2147,7 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 495,
|
||||
"width": 660,
|
||||
"height": 75.6
|
||||
},
|
||||
"_anchorPoint": {
|
||||
@@ -2186,8 +2186,8 @@
|
||||
"_string": "揭晓以下谐音梗的答案吧",
|
||||
"_horizontalAlign": 1,
|
||||
"_verticalAlign": 1,
|
||||
"_actualFontSize": 45,
|
||||
"_fontSize": 45,
|
||||
"_actualFontSize": 60,
|
||||
"_fontSize": 60,
|
||||
"_fontFamily": "Arial",
|
||||
"_lineHeight": 60,
|
||||
"_overflow": 0,
|
||||
@@ -2241,8 +2241,6 @@
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "90w8HRdbBPLYFqBkhPhWfM",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
@@ -2276,7 +2274,7 @@
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -8.201,
|
||||
"y": -852.319,
|
||||
"y": 492.399,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -2333,7 +2331,7 @@
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"y": -80.522,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -2345,9 +2343,9 @@
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
"x": 1.363,
|
||||
"y": 1.363,
|
||||
"z": 1.363
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1073741824,
|
||||
@@ -2494,7 +2492,7 @@
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -248.28,
|
||||
"x": -202.789,
|
||||
"y": -12.833,
|
||||
"z": 0
|
||||
},
|
||||
@@ -2507,9 +2505,9 @@
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0.537,
|
||||
"y": 0.537,
|
||||
"z": 0.767
|
||||
"x": 0.678,
|
||||
"y": 0.678,
|
||||
"z": 0.968
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1073741824,
|
||||
@@ -2789,9 +2787,9 @@
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0.488,
|
||||
"y": 0.488,
|
||||
"z": 0.488
|
||||
"x": 0.422,
|
||||
"y": 0.422,
|
||||
"z": 0.422
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1073741824,
|
||||
@@ -3839,8 +3837,6 @@
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "bdqvu61fVFTIU1TQqs/qES",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1668,7 +1668,7 @@
|
||||
"b": 0,
|
||||
"a": 255
|
||||
},
|
||||
"_string": "还差3题获得冷场小白2级",
|
||||
"_string": "还差3题,解锁新成就等级",
|
||||
"_horizontalAlign": 1,
|
||||
"_verticalAlign": 1,
|
||||
"_actualFontSize": 40,
|
||||
|
||||
@@ -93,7 +93,7 @@ export class PassModal extends BaseModal {
|
||||
private _titleInfo: PassModalTitleInfo = {
|
||||
titleText: '冷场小白1级',
|
||||
nextTitleProgress: 0,
|
||||
progressText: '还差3题获得冷场小白2级'
|
||||
progressText: '还差3题,解锁新成就等级'
|
||||
};
|
||||
|
||||
/** 动画起点。为 null 表示不做进度动画,直接展示终态 */
|
||||
@@ -105,7 +105,7 @@ export class PassModal extends BaseModal {
|
||||
/** 下一步按钮文案,为 null 时保留 prefab 默认值 */
|
||||
private _nextButtonText: string | null = null;
|
||||
|
||||
/** 进度游标 0% 时的本地 X 坐标,使用 prefab 当前摆放位置作为起点 */
|
||||
/** 进度游标 0% 时的本地 X 坐标,根据 ProgressBar Bar 子节点的左端推导出来 */
|
||||
private _progressAnchorStartX: number | null = null;
|
||||
|
||||
setParams(params: PassModalParams): void {
|
||||
@@ -400,11 +400,24 @@ export class PassModal extends BaseModal {
|
||||
}
|
||||
|
||||
private _cacheProgressAnchorStartX(): void {
|
||||
if (this._progressAnchorStartX !== null || !this.progressAnchor) {
|
||||
if (this._progressAnchorStartX !== null || !this.titleProgressBar) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._progressAnchorStartX = this.progressAnchor.position.x;
|
||||
const barSprite = this.titleProgressBar.barSprite;
|
||||
if (!barSprite) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Bar 节点 anchor 为 (0, 0.5),其本地 position.x 即为进度条可视左端。
|
||||
// ProgressBar 与 ProgressAnchor 共享同一父节点(TitleLevel),
|
||||
// 因此把 Bar 的本地 X 按 ProgressBar 自身的位移与缩放映射到父节点空间,
|
||||
// 才是真正的「0% 起点」。直接拿 progressAnchor.position.x 当起点会导致
|
||||
// 气泡始终被 prefab 摆放偏移量带跑(实测偏右 ~24px)。
|
||||
// -40 为视觉微调,与 PageHome 保持一致。
|
||||
const progressBarNode = this.titleProgressBar.node;
|
||||
const barLocalX = barSprite.node.position.x;
|
||||
this._progressAnchorStartX = progressBarNode.position.x + barLocalX * progressBarNode.scale.x - 30;
|
||||
}
|
||||
|
||||
private _resolveProgressAnchor(): void {
|
||||
|
||||
@@ -101,7 +101,7 @@ export class AchievementTitleManager {
|
||||
titleText: currentStage.titleText,
|
||||
nextTitleText: nextStage.titleText,
|
||||
nextTitleProgress,
|
||||
progressText: `还差${remainingToNextTitle}题获得${nextStage.titleText}`,
|
||||
progressText: `还差${remainingToNextTitle}题,解锁新成就等级`,
|
||||
completedLevelCount,
|
||||
currentTitleStartCount: currentStage.startCount,
|
||||
nextTitleRequiredCount: nextStage.startCount,
|
||||
|
||||
147
assets/scripts/utils/ShareLaunchHandler.ts
Normal file
147
assets/scripts/utils/ShareLaunchHandler.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
import { WxSDK } from './WxSDK';
|
||||
import { ShareManager } from './ShareManager';
|
||||
import { AuthManager } from './AuthManager';
|
||||
import { ViewManager } from '../core/ViewManager';
|
||||
|
||||
/**
|
||||
* 分享启动监听器
|
||||
*
|
||||
* 微信小游戏未被杀掉、只是退到后台时,再次通过好友分享卡片打开小游戏,
|
||||
* 不会重新走启动链路(PageLoading 不会再跑),因此 `wx.getLaunchOptionsSync()`
|
||||
* 取到的 query 可能是上一次启动的旧值。这个 handler 通过 `wx.onShow`
|
||||
* 拿到最新的 query,检测 shareCode 变化后:
|
||||
* 1. 清掉旧的分享态
|
||||
* 2. 调用 `ShareManager.joinShare(code)` 拉取新的题单
|
||||
* 3. 直接打开 `PageLevel` 进入分享挑战
|
||||
*
|
||||
* 对应在 PageLevel 那侧通过 `onViewShow` 检测到 ShareManager.shareCode
|
||||
* 变化,重新走 `_reinitLevelSession`。
|
||||
*/
|
||||
export class ShareLaunchHandler {
|
||||
private static _instance: ShareLaunchHandler | null = null;
|
||||
|
||||
static get instance(): ShareLaunchHandler {
|
||||
if (!this._instance) {
|
||||
this._instance = new ShareLaunchHandler();
|
||||
}
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
/** 已经处理过的 shareCode,相同则不再重复 join */
|
||||
private _activeShareCode: string | null = null;
|
||||
|
||||
/** 是否正在处理一次 onShow 触发的 join 流程,避免并发 */
|
||||
private _isHandlingShow: boolean = false;
|
||||
|
||||
/** 是否已经初始化 */
|
||||
private _initialized: boolean = false;
|
||||
|
||||
private _showHandler = (res: { query?: Record<string, any> } | undefined) => {
|
||||
const code = WxSDK.extractShareCodeFromQuery(res?.query);
|
||||
if (!code) {
|
||||
return;
|
||||
}
|
||||
// 同一个 shareCode 且当前已经处于该分享态,无需重复处理
|
||||
if (code === this._activeShareCode && ShareManager.instance.isShareMode) {
|
||||
return;
|
||||
}
|
||||
// 即使不是新的 code,但如果 ShareManager 已经丢失了分享态(例如挑战完成被 clear),
|
||||
// 用户重新点同一个分享卡片仍然应当重新加入。
|
||||
void this._handleShareCode(code);
|
||||
};
|
||||
|
||||
private _hideHandler = () => {
|
||||
// 目前不在 onHide 时做任何破坏性操作;保留监听只为方便后续扩展
|
||||
// (比如:暂停倒计时、上报埋点)。
|
||||
console.log('[ShareLaunchHandler] 小游戏切到后台');
|
||||
};
|
||||
|
||||
/**
|
||||
* 在 main.onLoad 中调用,注册 wx.onShow / wx.onHide。
|
||||
* 同时把当前启动参数中的 shareCode 作为种子,避免初次冷启动时
|
||||
* 因 wx.onShow 也会被调用一次而重复触发分享流程。
|
||||
*/
|
||||
init(): void {
|
||||
if (this._initialized) {
|
||||
return;
|
||||
}
|
||||
this._initialized = true;
|
||||
|
||||
if (!WxSDK.isWechat()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 冷启动时先把当前 launch 中的 shareCode 标记成已处理,
|
||||
// 避免 wx.onShow 在初始展示时拿到同一个 code 又走一遍 join。
|
||||
this._activeShareCode = WxSDK.getShareCodeFromLaunch();
|
||||
|
||||
WxSDK.onAppShow(this._showHandler);
|
||||
WxSDK.onAppHide(this._hideHandler);
|
||||
|
||||
console.log('[ShareLaunchHandler] 已注册 onShow/onHide 监听');
|
||||
}
|
||||
|
||||
/**
|
||||
* 由 PageLoading 在初始 join 之后调用,把已处理的 shareCode 显式同步过来,
|
||||
* 让 onShow 收到相同 code 时不会重复 join。
|
||||
*/
|
||||
markActiveShareCode(code: string | null): void {
|
||||
this._activeShareCode = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 主动取消监听(一般无需调用,留作扩展)
|
||||
*/
|
||||
dispose(): void {
|
||||
if (!this._initialized) return;
|
||||
this._initialized = false;
|
||||
WxSDK.offAppShow(this._showHandler);
|
||||
WxSDK.offAppHide(this._hideHandler);
|
||||
}
|
||||
|
||||
private async _handleShareCode(code: string): Promise<void> {
|
||||
if (this._isHandlingShow) {
|
||||
console.log('[ShareLaunchHandler] 已有 onShow 分享流程在执行,跳过', code);
|
||||
return;
|
||||
}
|
||||
this._isHandlingShow = true;
|
||||
|
||||
try {
|
||||
console.log('[ShareLaunchHandler] 检测到新的 shareCode,准备切换:', code);
|
||||
|
||||
// 确保已登录(initialize 内部对已有 token 做了校验,幂等可重复调用)
|
||||
const loginOk = await AuthManager.instance.initialize();
|
||||
if (!loginOk) {
|
||||
console.warn('[ShareLaunchHandler] 登录失败,放弃 onShow 分享切换');
|
||||
return;
|
||||
}
|
||||
|
||||
// 切到新的分享前清掉旧分享态,避免 ShareManager 内残留旧题单导致 PageLevel 错位
|
||||
if (ShareManager.instance.isShareMode) {
|
||||
ShareManager.instance.clearShareMode();
|
||||
}
|
||||
|
||||
const joinOk = await ShareManager.instance.joinShare(code);
|
||||
if (!joinOk) {
|
||||
console.warn('[ShareLaunchHandler] 加入分享失败:', code);
|
||||
return;
|
||||
}
|
||||
|
||||
// 标记当前激活的分享码
|
||||
this._activeShareCode = code;
|
||||
|
||||
// 跳过中间页,直接打开 PageLevel 进入分享挑战。
|
||||
// PageLevel 会在 onViewShow 中根据 ShareManager.shareCode 与本地缓存比对,
|
||||
// 决定是否需要 `_reinitLevelSession`。
|
||||
ViewManager.instance.open('PageLevel', {
|
||||
params: { shareMode: true },
|
||||
});
|
||||
|
||||
console.log('[ShareLaunchHandler] 已切换到分享挑战:', code);
|
||||
} catch (err) {
|
||||
console.error('[ShareLaunchHandler] 处理 shareCode 异常:', err);
|
||||
} finally {
|
||||
this._isHandlingShow = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
assets/scripts/utils/ShareLaunchHandler.ts.meta
Normal file
9
assets/scripts/utils/ShareLaunchHandler.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "0709f849-66c8-4e4c-aec5-044c3c414c3e",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -398,15 +398,82 @@ export class WxSDK {
|
||||
|
||||
try {
|
||||
const options = wxApi.getLaunchOptionsSync();
|
||||
if (options?.query?.shareCode) {
|
||||
console.log('[WxSDK] 检测到分享码:', options.query.shareCode);
|
||||
return options.query.shareCode;
|
||||
const code = WxSDK.extractShareCodeFromQuery(options?.query);
|
||||
if (code) {
|
||||
console.log('[WxSDK] 检测到分享码:', code);
|
||||
return code;
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('[WxSDK] 获取启动参数失败:', err);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从查询对象(来自 launch options 或 onShow 回调)中提取 shareCode
|
||||
*/
|
||||
static extractShareCodeFromQuery(query: Record<string, any> | null | undefined): string | null {
|
||||
const code = query?.shareCode;
|
||||
return typeof code === 'string' && code.length > 0 ? code : null;
|
||||
}
|
||||
|
||||
// ==================== 前后台生命周期 ====================
|
||||
|
||||
/**
|
||||
* 监听小游戏切到前台事件。
|
||||
* 同一个回调可重复注册多次:内部用 wx.onShow,请确保业务层做幂等处理或在卸载时调用 offAppShow。
|
||||
* @param callback 切前台时触发,包含本次显示对应的 query / scene 等参数
|
||||
*/
|
||||
static onAppShow(callback: (res: { query?: Record<string, any>; scene?: number; path?: string } | undefined) => void): void {
|
||||
const wxApi = WxSDK.getWx();
|
||||
if (!wxApi) return;
|
||||
|
||||
if (typeof wxApi.onShow !== 'function') {
|
||||
console.warn('[WxSDK] 当前微信版本不支持 onShow');
|
||||
return;
|
||||
}
|
||||
|
||||
wxApi.onShow(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消监听小游戏切到前台事件
|
||||
*/
|
||||
static offAppShow(callback: (res: any) => void): void {
|
||||
const wxApi = WxSDK.getWx();
|
||||
if (!wxApi) return;
|
||||
|
||||
if (typeof wxApi.offShow === 'function') {
|
||||
wxApi.offShow(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听小游戏切到后台事件
|
||||
*/
|
||||
static onAppHide(callback: () => void): void {
|
||||
const wxApi = WxSDK.getWx();
|
||||
if (!wxApi) return;
|
||||
|
||||
if (typeof wxApi.onHide !== 'function') {
|
||||
console.warn('[WxSDK] 当前微信版本不支持 onHide');
|
||||
return;
|
||||
}
|
||||
|
||||
wxApi.onHide(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消监听小游戏切到后台事件
|
||||
*/
|
||||
static offAppHide(callback: () => void): void {
|
||||
const wxApi = WxSDK.getWx();
|
||||
if (!wxApi) return;
|
||||
|
||||
if (typeof wxApi.offHide === 'function') {
|
||||
wxApi.offHide(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 隐私授权相关 ====================
|
||||
|
||||
6
settings/mcp-server.json
Normal file
6
settings/mcp-server.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"port": 3008,
|
||||
"autoStart": false,
|
||||
"enableDebugLog": false,
|
||||
"maxConnections": 10
|
||||
}
|
||||
957
settings/tool-manager.json
Normal file
957
settings/tool-manager.json
Normal file
@@ -0,0 +1,957 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"id": "4e401ac4-fa11-4f3b-9531-bb09687de4df",
|
||||
"name": "默认配置",
|
||||
"description": "自动创建的默认工具配置",
|
||||
"tools": [
|
||||
{
|
||||
"category": "scene",
|
||||
"name": "get_current_scene",
|
||||
"enabled": true,
|
||||
"description": "Get current scene information"
|
||||
},
|
||||
{
|
||||
"category": "scene",
|
||||
"name": "get_scene_list",
|
||||
"enabled": true,
|
||||
"description": "Get all scenes in the project"
|
||||
},
|
||||
{
|
||||
"category": "scene",
|
||||
"name": "open_scene",
|
||||
"enabled": true,
|
||||
"description": "Open a scene by path"
|
||||
},
|
||||
{
|
||||
"category": "scene",
|
||||
"name": "save_scene",
|
||||
"enabled": true,
|
||||
"description": "Save current scene"
|
||||
},
|
||||
{
|
||||
"category": "scene",
|
||||
"name": "create_scene",
|
||||
"enabled": true,
|
||||
"description": "Create a new scene asset"
|
||||
},
|
||||
{
|
||||
"category": "scene",
|
||||
"name": "save_scene_as",
|
||||
"enabled": true,
|
||||
"description": "Save scene as new file"
|
||||
},
|
||||
{
|
||||
"category": "scene",
|
||||
"name": "close_scene",
|
||||
"enabled": true,
|
||||
"description": "Close current scene"
|
||||
},
|
||||
{
|
||||
"category": "scene",
|
||||
"name": "get_scene_hierarchy",
|
||||
"enabled": true,
|
||||
"description": "Get the complete hierarchy of current scene"
|
||||
},
|
||||
{
|
||||
"category": "node",
|
||||
"name": "create_node",
|
||||
"enabled": true,
|
||||
"description": "Create a new node in the scene. Supports creating empty nodes, nodes with components, or instantiating from assets (prefabs, etc.). IMPORTANT: You should always provide parentUuid to specify where to create the node."
|
||||
},
|
||||
{
|
||||
"category": "node",
|
||||
"name": "get_node_info",
|
||||
"enabled": true,
|
||||
"description": "Get node information by UUID"
|
||||
},
|
||||
{
|
||||
"category": "node",
|
||||
"name": "find_nodes",
|
||||
"enabled": true,
|
||||
"description": "Find nodes by name pattern"
|
||||
},
|
||||
{
|
||||
"category": "node",
|
||||
"name": "find_node_by_name",
|
||||
"enabled": true,
|
||||
"description": "Find first node by exact name"
|
||||
},
|
||||
{
|
||||
"category": "node",
|
||||
"name": "get_all_nodes",
|
||||
"enabled": true,
|
||||
"description": "Get all nodes in the scene with their UUIDs"
|
||||
},
|
||||
{
|
||||
"category": "node",
|
||||
"name": "set_node_property",
|
||||
"enabled": true,
|
||||
"description": "Set node property value (prefer using set_node_transform for active/layer/mobility/position/rotation/scale)"
|
||||
},
|
||||
{
|
||||
"category": "node",
|
||||
"name": "set_node_transform",
|
||||
"enabled": true,
|
||||
"description": "Set node transform properties (position, rotation, scale) with unified interface. Automatically handles 2D/3D node differences."
|
||||
},
|
||||
{
|
||||
"category": "node",
|
||||
"name": "delete_node",
|
||||
"enabled": true,
|
||||
"description": "Delete a node from scene"
|
||||
},
|
||||
{
|
||||
"category": "node",
|
||||
"name": "move_node",
|
||||
"enabled": true,
|
||||
"description": "Move node to new parent"
|
||||
},
|
||||
{
|
||||
"category": "node",
|
||||
"name": "duplicate_node",
|
||||
"enabled": true,
|
||||
"description": "Duplicate a node"
|
||||
},
|
||||
{
|
||||
"category": "node",
|
||||
"name": "detect_node_type",
|
||||
"enabled": true,
|
||||
"description": "Detect if a node is 2D or 3D based on its components and properties"
|
||||
},
|
||||
{
|
||||
"category": "component",
|
||||
"name": "add_component",
|
||||
"enabled": true,
|
||||
"description": "Add a component to a specific node. IMPORTANT: You must provide the nodeUuid parameter to specify which node to add the component to."
|
||||
},
|
||||
{
|
||||
"category": "component",
|
||||
"name": "remove_component",
|
||||
"enabled": true,
|
||||
"description": "Remove a component from a node. componentType must be the component's classId (cid, i.e. the type field from getComponents), not the script name or class name. Use getComponents to get the correct cid."
|
||||
},
|
||||
{
|
||||
"category": "component",
|
||||
"name": "get_components",
|
||||
"enabled": true,
|
||||
"description": "Get all components of a node"
|
||||
},
|
||||
{
|
||||
"category": "component",
|
||||
"name": "get_component_info",
|
||||
"enabled": true,
|
||||
"description": "Get specific component information"
|
||||
},
|
||||
{
|
||||
"category": "component",
|
||||
"name": "set_component_property",
|
||||
"enabled": true,
|
||||
"description": "Set component property values for UI components or custom script components. Supports setting properties of built-in UI components (e.g., cc.Label, cc.Sprite) and custom script components. Note: For node basic properties (name, active, layer, etc.), use set_node_property. For node transform properties (position, rotation, scale, etc.), use set_node_transform."
|
||||
},
|
||||
{
|
||||
"category": "component",
|
||||
"name": "attach_script",
|
||||
"enabled": true,
|
||||
"description": "Attach a script component to a node"
|
||||
},
|
||||
{
|
||||
"category": "component",
|
||||
"name": "get_available_components",
|
||||
"enabled": true,
|
||||
"description": "Get list of available component types"
|
||||
},
|
||||
{
|
||||
"category": "prefab",
|
||||
"name": "get_prefab_list",
|
||||
"enabled": true,
|
||||
"description": "Get all prefabs in the project"
|
||||
},
|
||||
{
|
||||
"category": "prefab",
|
||||
"name": "load_prefab",
|
||||
"enabled": true,
|
||||
"description": "Load a prefab by path"
|
||||
},
|
||||
{
|
||||
"category": "prefab",
|
||||
"name": "instantiate_prefab",
|
||||
"enabled": true,
|
||||
"description": "Instantiate a prefab in the scene"
|
||||
},
|
||||
{
|
||||
"category": "prefab",
|
||||
"name": "create_prefab",
|
||||
"enabled": true,
|
||||
"description": "Create a prefab from a node with all children and components"
|
||||
},
|
||||
{
|
||||
"category": "prefab",
|
||||
"name": "update_prefab",
|
||||
"enabled": true,
|
||||
"description": "Update an existing prefab"
|
||||
},
|
||||
{
|
||||
"category": "prefab",
|
||||
"name": "revert_prefab",
|
||||
"enabled": true,
|
||||
"description": "Revert prefab instance to original"
|
||||
},
|
||||
{
|
||||
"category": "prefab",
|
||||
"name": "get_prefab_info",
|
||||
"enabled": true,
|
||||
"description": "Get detailed prefab information"
|
||||
},
|
||||
{
|
||||
"category": "prefab",
|
||||
"name": "validate_prefab",
|
||||
"enabled": true,
|
||||
"description": "Validate a prefab file format"
|
||||
},
|
||||
{
|
||||
"category": "prefab",
|
||||
"name": "duplicate_prefab",
|
||||
"enabled": true,
|
||||
"description": "Duplicate an existing prefab"
|
||||
},
|
||||
{
|
||||
"category": "prefab",
|
||||
"name": "restore_prefab_node",
|
||||
"enabled": true,
|
||||
"description": "Restore prefab node using prefab asset (built-in undo record)"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "run_project",
|
||||
"enabled": true,
|
||||
"description": "Run the project in preview mode"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "build_project",
|
||||
"enabled": true,
|
||||
"description": "Build the project"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "get_project_info",
|
||||
"enabled": true,
|
||||
"description": "Get project information"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "get_project_settings",
|
||||
"enabled": true,
|
||||
"description": "Get project settings"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "refresh_assets",
|
||||
"enabled": true,
|
||||
"description": "Refresh asset database"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "import_asset",
|
||||
"enabled": true,
|
||||
"description": "Import an asset file"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "get_asset_info",
|
||||
"enabled": true,
|
||||
"description": "Get asset information"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "get_assets",
|
||||
"enabled": true,
|
||||
"description": "Get assets by type"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "get_build_settings",
|
||||
"enabled": true,
|
||||
"description": "Get build settings - shows current limitations"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "open_build_panel",
|
||||
"enabled": true,
|
||||
"description": "Open the build panel in the editor"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "check_builder_status",
|
||||
"enabled": true,
|
||||
"description": "Check if builder worker is ready"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "start_preview_server",
|
||||
"enabled": true,
|
||||
"description": "Start preview server"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "stop_preview_server",
|
||||
"enabled": true,
|
||||
"description": "Stop preview server"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "create_asset",
|
||||
"enabled": true,
|
||||
"description": "Create a new asset file or folder"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "copy_asset",
|
||||
"enabled": true,
|
||||
"description": "Copy an asset to another location"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "move_asset",
|
||||
"enabled": true,
|
||||
"description": "Move an asset to another location"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "delete_asset",
|
||||
"enabled": true,
|
||||
"description": "Delete an asset"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "save_asset",
|
||||
"enabled": true,
|
||||
"description": "Save asset content"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "reimport_asset",
|
||||
"enabled": true,
|
||||
"description": "Reimport an asset"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "query_asset_path",
|
||||
"enabled": true,
|
||||
"description": "Get asset disk path"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "query_asset_uuid",
|
||||
"enabled": true,
|
||||
"description": "Get asset UUID from URL"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "query_asset_url",
|
||||
"enabled": true,
|
||||
"description": "Get asset URL from UUID"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "find_asset_by_name",
|
||||
"enabled": true,
|
||||
"description": "Find assets by name (supports partial matching and multiple results)"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "get_asset_details",
|
||||
"enabled": true,
|
||||
"description": "Get detailed asset information including spriteFrame sub-assets"
|
||||
},
|
||||
{
|
||||
"category": "debug",
|
||||
"name": "get_console_logs",
|
||||
"enabled": true,
|
||||
"description": "Get editor console logs"
|
||||
},
|
||||
{
|
||||
"category": "debug",
|
||||
"name": "clear_console",
|
||||
"enabled": true,
|
||||
"description": "Clear editor console"
|
||||
},
|
||||
{
|
||||
"category": "debug",
|
||||
"name": "execute_script",
|
||||
"enabled": true,
|
||||
"description": "Execute JavaScript in scene context"
|
||||
},
|
||||
{
|
||||
"category": "debug",
|
||||
"name": "get_node_tree",
|
||||
"enabled": true,
|
||||
"description": "Get detailed node tree for debugging"
|
||||
},
|
||||
{
|
||||
"category": "debug",
|
||||
"name": "get_performance_stats",
|
||||
"enabled": true,
|
||||
"description": "Get performance statistics"
|
||||
},
|
||||
{
|
||||
"category": "debug",
|
||||
"name": "validate_scene",
|
||||
"enabled": true,
|
||||
"description": "Validate current scene for issues"
|
||||
},
|
||||
{
|
||||
"category": "debug",
|
||||
"name": "get_editor_info",
|
||||
"enabled": true,
|
||||
"description": "Get editor and environment information"
|
||||
},
|
||||
{
|
||||
"category": "debug",
|
||||
"name": "get_project_logs",
|
||||
"enabled": true,
|
||||
"description": "Get project logs from temp/logs/project.log file"
|
||||
},
|
||||
{
|
||||
"category": "debug",
|
||||
"name": "get_log_file_info",
|
||||
"enabled": true,
|
||||
"description": "Get information about the project log file"
|
||||
},
|
||||
{
|
||||
"category": "debug",
|
||||
"name": "search_project_logs",
|
||||
"enabled": true,
|
||||
"description": "Search for specific patterns or errors in project logs"
|
||||
},
|
||||
{
|
||||
"category": "preferences",
|
||||
"name": "open_preferences_settings",
|
||||
"enabled": true,
|
||||
"description": "Open preferences settings panel"
|
||||
},
|
||||
{
|
||||
"category": "preferences",
|
||||
"name": "query_preferences_config",
|
||||
"enabled": true,
|
||||
"description": "Query preferences configuration"
|
||||
},
|
||||
{
|
||||
"category": "preferences",
|
||||
"name": "set_preferences_config",
|
||||
"enabled": true,
|
||||
"description": "Set preferences configuration"
|
||||
},
|
||||
{
|
||||
"category": "preferences",
|
||||
"name": "get_all_preferences",
|
||||
"enabled": true,
|
||||
"description": "Get all available preferences categories"
|
||||
},
|
||||
{
|
||||
"category": "preferences",
|
||||
"name": "reset_preferences",
|
||||
"enabled": true,
|
||||
"description": "Reset preferences to default values"
|
||||
},
|
||||
{
|
||||
"category": "preferences",
|
||||
"name": "export_preferences",
|
||||
"enabled": true,
|
||||
"description": "Export current preferences configuration"
|
||||
},
|
||||
{
|
||||
"category": "preferences",
|
||||
"name": "import_preferences",
|
||||
"enabled": true,
|
||||
"description": "Import preferences configuration from file"
|
||||
},
|
||||
{
|
||||
"category": "server",
|
||||
"name": "query_server_ip_list",
|
||||
"enabled": true,
|
||||
"description": "Query server IP list"
|
||||
},
|
||||
{
|
||||
"category": "server",
|
||||
"name": "query_sorted_server_ip_list",
|
||||
"enabled": true,
|
||||
"description": "Get sorted server IP list"
|
||||
},
|
||||
{
|
||||
"category": "server",
|
||||
"name": "query_server_port",
|
||||
"enabled": true,
|
||||
"description": "Query editor server current port"
|
||||
},
|
||||
{
|
||||
"category": "server",
|
||||
"name": "get_server_status",
|
||||
"enabled": true,
|
||||
"description": "Get comprehensive server status information"
|
||||
},
|
||||
{
|
||||
"category": "server",
|
||||
"name": "check_server_connectivity",
|
||||
"enabled": true,
|
||||
"description": "Check server connectivity and network status"
|
||||
},
|
||||
{
|
||||
"category": "server",
|
||||
"name": "get_network_interfaces",
|
||||
"enabled": true,
|
||||
"description": "Get available network interfaces"
|
||||
},
|
||||
{
|
||||
"category": "broadcast",
|
||||
"name": "get_broadcast_log",
|
||||
"enabled": true,
|
||||
"description": "Get recent broadcast messages log"
|
||||
},
|
||||
{
|
||||
"category": "broadcast",
|
||||
"name": "listen_broadcast",
|
||||
"enabled": true,
|
||||
"description": "Start listening for specific broadcast messages"
|
||||
},
|
||||
{
|
||||
"category": "broadcast",
|
||||
"name": "stop_listening",
|
||||
"enabled": true,
|
||||
"description": "Stop listening for specific broadcast messages"
|
||||
},
|
||||
{
|
||||
"category": "broadcast",
|
||||
"name": "clear_broadcast_log",
|
||||
"enabled": true,
|
||||
"description": "Clear the broadcast messages log"
|
||||
},
|
||||
{
|
||||
"category": "broadcast",
|
||||
"name": "get_active_listeners",
|
||||
"enabled": true,
|
||||
"description": "Get list of active broadcast listeners"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "reset_node_property",
|
||||
"enabled": true,
|
||||
"description": "Reset node property to default value"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "move_array_element",
|
||||
"enabled": true,
|
||||
"description": "Move array element position"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "remove_array_element",
|
||||
"enabled": true,
|
||||
"description": "Remove array element at specific index"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "copy_node",
|
||||
"enabled": true,
|
||||
"description": "Copy node for later paste operation"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "paste_node",
|
||||
"enabled": true,
|
||||
"description": "Paste previously copied nodes"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "cut_node",
|
||||
"enabled": true,
|
||||
"description": "Cut node (copy + mark for move)"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "reset_node_transform",
|
||||
"enabled": true,
|
||||
"description": "Reset node position, rotation and scale"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "reset_component",
|
||||
"enabled": true,
|
||||
"description": "Reset component to default values"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "restore_prefab",
|
||||
"enabled": true,
|
||||
"description": "Restore prefab instance from asset"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "execute_component_method",
|
||||
"enabled": true,
|
||||
"description": "Execute method on component"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "execute_scene_script",
|
||||
"enabled": true,
|
||||
"description": "Execute scene script method"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "scene_snapshot",
|
||||
"enabled": true,
|
||||
"description": "Create scene state snapshot"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "scene_snapshot_abort",
|
||||
"enabled": true,
|
||||
"description": "Abort scene snapshot creation"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "begin_undo_recording",
|
||||
"enabled": true,
|
||||
"description": "Begin recording undo data"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "end_undo_recording",
|
||||
"enabled": true,
|
||||
"description": "End recording undo data"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "cancel_undo_recording",
|
||||
"enabled": true,
|
||||
"description": "Cancel undo recording"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "soft_reload_scene",
|
||||
"enabled": true,
|
||||
"description": "Soft reload current scene"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "query_scene_ready",
|
||||
"enabled": true,
|
||||
"description": "Check if scene is ready"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "query_scene_dirty",
|
||||
"enabled": true,
|
||||
"description": "Check if scene has unsaved changes"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "query_scene_classes",
|
||||
"enabled": true,
|
||||
"description": "Query all registered classes"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "query_scene_components",
|
||||
"enabled": true,
|
||||
"description": "Query available scene components"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "query_component_has_script",
|
||||
"enabled": true,
|
||||
"description": "Check if component has script"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "query_nodes_by_asset_uuid",
|
||||
"enabled": true,
|
||||
"description": "Find nodes that use specific asset UUID"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "change_gizmo_tool",
|
||||
"enabled": true,
|
||||
"description": "Change Gizmo tool"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "query_gizmo_tool_name",
|
||||
"enabled": true,
|
||||
"description": "Get current Gizmo tool name"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "change_gizmo_pivot",
|
||||
"enabled": true,
|
||||
"description": "Change transform pivot point"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "query_gizmo_pivot",
|
||||
"enabled": true,
|
||||
"description": "Get current Gizmo pivot point"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "query_gizmo_view_mode",
|
||||
"enabled": true,
|
||||
"description": "Query view mode (view/select)"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "change_gizmo_coordinate",
|
||||
"enabled": true,
|
||||
"description": "Change coordinate system"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "query_gizmo_coordinate",
|
||||
"enabled": true,
|
||||
"description": "Get current coordinate system"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "change_view_mode_2d_3d",
|
||||
"enabled": true,
|
||||
"description": "Change 2D/3D view mode"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "query_view_mode_2d_3d",
|
||||
"enabled": true,
|
||||
"description": "Get current view mode"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "set_grid_visible",
|
||||
"enabled": true,
|
||||
"description": "Show/hide grid"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "query_grid_visible",
|
||||
"enabled": true,
|
||||
"description": "Query grid visibility status"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "set_icon_gizmo_3d",
|
||||
"enabled": true,
|
||||
"description": "Set IconGizmo to 3D or 2D mode"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "query_icon_gizmo_3d",
|
||||
"enabled": true,
|
||||
"description": "Query IconGizmo mode"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "set_icon_gizmo_size",
|
||||
"enabled": true,
|
||||
"description": "Set IconGizmo size"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "query_icon_gizmo_size",
|
||||
"enabled": true,
|
||||
"description": "Query IconGizmo size"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "focus_camera_on_nodes",
|
||||
"enabled": true,
|
||||
"description": "Focus scene camera on nodes"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "align_camera_with_view",
|
||||
"enabled": true,
|
||||
"description": "Apply scene camera position and angle to selected node"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "align_view_with_node",
|
||||
"enabled": true,
|
||||
"description": "Apply selected node position and angle to current view"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "get_scene_view_status",
|
||||
"enabled": true,
|
||||
"description": "Get comprehensive scene view status"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "reset_scene_view",
|
||||
"enabled": true,
|
||||
"description": "Reset scene view to default settings"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "add_reference_image",
|
||||
"enabled": true,
|
||||
"description": "Add reference image(s) to scene"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "remove_reference_image",
|
||||
"enabled": true,
|
||||
"description": "Remove reference image(s)"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "switch_reference_image",
|
||||
"enabled": true,
|
||||
"description": "Switch to specific reference image"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "set_reference_image_data",
|
||||
"enabled": true,
|
||||
"description": "Set reference image transform and display properties"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "query_reference_image_config",
|
||||
"enabled": true,
|
||||
"description": "Query reference image configuration"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "query_current_reference_image",
|
||||
"enabled": true,
|
||||
"description": "Query current reference image data"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "refresh_reference_image",
|
||||
"enabled": true,
|
||||
"description": "Refresh reference image display"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "set_reference_image_position",
|
||||
"enabled": true,
|
||||
"description": "Set reference image position"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "set_reference_image_scale",
|
||||
"enabled": true,
|
||||
"description": "Set reference image scale"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "set_reference_image_opacity",
|
||||
"enabled": true,
|
||||
"description": "Set reference image opacity"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "list_reference_images",
|
||||
"enabled": true,
|
||||
"description": "List all available reference images"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "clear_all_reference_images",
|
||||
"enabled": true,
|
||||
"description": "Clear all reference images"
|
||||
},
|
||||
{
|
||||
"category": "assetAdvanced",
|
||||
"name": "save_asset_meta",
|
||||
"enabled": true,
|
||||
"description": "Save asset meta information"
|
||||
},
|
||||
{
|
||||
"category": "assetAdvanced",
|
||||
"name": "generate_available_url",
|
||||
"enabled": true,
|
||||
"description": "Generate an available URL based on input URL"
|
||||
},
|
||||
{
|
||||
"category": "assetAdvanced",
|
||||
"name": "query_asset_db_ready",
|
||||
"enabled": true,
|
||||
"description": "Check if asset database is ready"
|
||||
},
|
||||
{
|
||||
"category": "assetAdvanced",
|
||||
"name": "open_asset_external",
|
||||
"enabled": true,
|
||||
"description": "Open asset with external program"
|
||||
},
|
||||
{
|
||||
"category": "assetAdvanced",
|
||||
"name": "batch_import_assets",
|
||||
"enabled": true,
|
||||
"description": "Import multiple assets in batch"
|
||||
},
|
||||
{
|
||||
"category": "assetAdvanced",
|
||||
"name": "batch_delete_assets",
|
||||
"enabled": true,
|
||||
"description": "Delete multiple assets in batch"
|
||||
},
|
||||
{
|
||||
"category": "assetAdvanced",
|
||||
"name": "validate_asset_references",
|
||||
"enabled": true,
|
||||
"description": "Validate asset references and find broken links"
|
||||
},
|
||||
{
|
||||
"category": "assetAdvanced",
|
||||
"name": "get_asset_dependencies",
|
||||
"enabled": true,
|
||||
"description": "Get asset dependency tree"
|
||||
},
|
||||
{
|
||||
"category": "assetAdvanced",
|
||||
"name": "get_unused_assets",
|
||||
"enabled": true,
|
||||
"description": "Find unused assets in project"
|
||||
},
|
||||
{
|
||||
"category": "assetAdvanced",
|
||||
"name": "compress_textures",
|
||||
"enabled": true,
|
||||
"description": "Batch compress texture assets"
|
||||
},
|
||||
{
|
||||
"category": "assetAdvanced",
|
||||
"name": "export_asset_manifest",
|
||||
"enabled": true,
|
||||
"description": "Export asset manifest/inventory"
|
||||
},
|
||||
{
|
||||
"category": "validation",
|
||||
"name": "validate_json_params",
|
||||
"enabled": true,
|
||||
"description": "Validate and fix JSON parameters before sending to other tools"
|
||||
},
|
||||
{
|
||||
"category": "validation",
|
||||
"name": "safe_string_value",
|
||||
"enabled": true,
|
||||
"description": "Create a safe string value that won't cause JSON parsing issues"
|
||||
},
|
||||
{
|
||||
"category": "validation",
|
||||
"name": "format_mcp_request",
|
||||
"enabled": true,
|
||||
"description": "Format a complete MCP request with proper JSON escaping"
|
||||
}
|
||||
],
|
||||
"createdAt": "2026-05-19T14:37:17.528Z",
|
||||
"updatedAt": "2026-05-19T14:37:17.528Z"
|
||||
}
|
||||
],
|
||||
"currentConfigId": "4e401ac4-fa11-4f3b-9531-bb09687de4df",
|
||||
"maxConfigSlots": 5
|
||||
}
|
||||
Reference in New Issue
Block a user