Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
010696c
feat: add createFrame and removeFrame
xiaoxustudio Mar 11, 2026
ab43666
feat: add iframe api and reactive store
xiaoxustudio Mar 12, 2026
8d5c075
refactor: extract iframe interfaces
xiaoxustudio Mar 12, 2026
a073635
feat: add iframe wait and return value support
xiaoxustudio Mar 12, 2026
2a83f74
fix: handle iframe load error
xiaoxustudio Mar 12, 2026
e1976ee
chore: resolve some issues
xiaoxustudio Mar 12, 2026
dd454ff
fix: restrict iframe postMessage origin
xiaoxustudio Mar 12, 2026
3b82c42
feat: add iframe setGameVar and closeFrame API
xiaoxustudio Mar 12, 2026
d422882
refactor: simplify iframe component logic
xiaoxustudio Mar 13, 2026
3f00f64
feat: add iframe nextSentence and isBlockSentence API
xiaoxustudio Mar 13, 2026
029788c
feat: add iframe save and load events
xiaoxustudio Mar 13, 2026
3722839
fix: iframe width and height is invalid
xiaoxustudio Mar 13, 2026
a10af41
chore: unified name
xiaoxustudio Mar 14, 2026
33aee01
fix: unified function name
xiaoxustudio Mar 14, 2026
0cc054f
fix: build error
xiaoxustudio Mar 14, 2026
36b6017
fix: rename closeFrame to closeIframe
xiaoxustudio Mar 15, 2026
3545310
fix: reset iframe state when continue game
xiaoxustudio Mar 15, 2026
e65cc77
fix: isBlockSentence always return false when the second
xiaoxustudio Mar 15, 2026
d43cdb4
feat: add iframe persistent data API
xiaoxustudio Mar 15, 2026
32f6aee
feat: add iframe open/close and isActive state
xiaoxustudio Mar 17, 2026
ddbce3f
fix: set iframe isActive to true when adding
xiaoxustudio Mar 17, 2026
60440ed
feat: add command input parameters
xiaoxustudio Mar 19, 2026
ea691a8
feat: add postIframeMessage API
xiaoxustudio Mar 19, 2026
8ba8618
feat: add hidden parameter and style support for iframe
xiaoxustudio Mar 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/parser/src/config/scriptConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ export const SCRIPT_CONFIG = [
{ scriptString: 'applyStyle', scriptType: commandType.applyStyle },
{ scriptString: 'wait', scriptType: commandType.wait },
{ scriptString: 'callSteam', scriptType: commandType.callSteam },
{ scriptString: 'createFrame', scriptType: commandType.createFrame },
{ scriptString: 'removeFrame', scriptType: commandType.removeFrame },
];
export const ADD_NEXT_ARG_LIST = [
commandType.bgm,
Expand Down
2 changes: 2 additions & 0 deletions packages/parser/src/interface/sceneInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ export enum commandType {
applyStyle,
wait,
callSteam, // 调用Steam功能
createFrame, // 创建框架
removeFrame, // 移除框架
}

/**
Expand Down
21 changes: 21 additions & 0 deletions packages/webgal/src/Core/controller/frame/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const frameApiManager = new (class {
private apis: Record<string, Function>;
public constructor() {
this.apis = {};
}
public registerFrameApi(fnName: string, fn: Function) {
this.apis[fnName] = fn;
}
public callFrameApi(fnName: string, ...args: any[]) {
if (this.apis[fnName]) {
this.apis[fnName](...args);
}
}
public clearFrameApi() {
this.apis = {};
}
public getFrameApi(fnName: string) {
return this.apis[fnName];
}
})();
Comment thread
xiaoxustudio marked this conversation as resolved.
Outdated
export default frameApiManager;
2 changes: 2 additions & 0 deletions packages/webgal/src/Core/controller/scene/sceneInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ export enum commandType {
applyStyle,
wait,
callSteam, // 调用Steam功能
createFrame, // 创建框架
removeFrame, // 移除框架
}

/**
Expand Down
5 changes: 4 additions & 1 deletion packages/webgal/src/Core/controller/stage/resetStage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { initState, resetStageState, setStage } from '@/store/stageReducer';
import { initState, resetStageState, setStage, stageActions } from '@/store/stageReducer';
import { webgalStore } from '@/store/store';
import cloneDeep from 'lodash/cloneDeep';
import { WebGAL } from '@/Core/WebGAL';
Expand Down Expand Up @@ -27,4 +27,7 @@ export const resetStage = (resetBacklog: boolean, resetSceneAndVar = true) => {
if (!resetSceneAndVar) {
webgalStore.dispatch(setStage({ key: 'GameVar', value: currentVars }));
}

// 清空frames
webgalStore.dispatch(stageActions.resetFrame());
};
120 changes: 120 additions & 0 deletions packages/webgal/src/Core/gameScripts/createFrame.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { ISentence } from '@/Core/controller/scene/sceneInterface';
import { IPerform } from '@/Core/Modules/perform/performInterface';
import { getBooleanArgByKey, getNumberArgByKey, getStringArgByKey } from '../util/getSentenceArg';
import { IIFrame } from '@/store/stageInterface';
import { webgalStore } from '@/store/store';
import { stageActions } from '@/store/stageReducer';

const allSandboxProperties = {
'allow-forms': 'allowForms', // 允许iframe内提交表单
'allow-scripts': 'allowScripts', // 允许iframe内执行JavaScript脚本(包括定时器、事件等)
'allow-same-origin': 'allowSameOrigin', // 允许iframe内容拥有同源身份,可访问自身Cookie/LocalStorage等
'allow-top-navigation': 'allowTopNavigation', // 允许iframe内的链接跳转到父页面(主页面)的上下文
'allow-popups': 'allowPopups', // 允许iframe通过window.open()等方式弹出新窗口
'allow-modals': 'allowModals', // 允许iframe弹出模态窗口(如alert()、confirm()、prompt())
'allow-pointer-lock': 'allowPointerLock', // 允许iframe使用Pointer Lock API(如游戏鼠标锁定)
'allow-popups-to-escape-sandbox': 'allowPopupsToEscapeSandbox', // 允许iframe弹出的新窗口不受当前沙箱限制
'allow-downloads': 'allowDownloads', // 允许iframe内触发文件下载操作
'allow-presentation': 'allowPresentation', // 允许iframe使用Presentation API(投屏/演示功能)
'allow-top-navigation-by-user-activation': 'allowTopNavigationByUserActivation', // 仅允许用户主动触发(如点击)的顶级导航操作
'allow-storage-access-by-user-activation': 'allowStorageAccessByUserActivation', // 允许用户主动触发后访问父页面的存储权限
'allow-orientation-lock': 'allowOrientationLock', // 允许iframe使用Screen Orientation API锁定屏幕方向
};

/**
* 创建框架
* @param sentence
*/
export const createFrame = (sentence: ISentence): IPerform => {
const src = sentence.content;
const id = getStringArgByKey(sentence, 'id') ?? '';
const wait = getBooleanArgByKey(sentence, 'wait') ?? false;
const returnValue = getStringArgByKey(sentence, 'returnValue') ?? null;
const width = getNumberArgByKey(sentence, 'width') ?? undefined;
const height = getNumberArgByKey(sentence, 'height') ?? undefined;
if (!id || !src) {
return {
performName: 'none',
duration: 0,
isHoldOn: false,
stopFunction: () => {},
blockingNext: () => false,
blockingAuto: () => true,
stopTimeout: undefined,
};
}

let rawSrc = src;
// 处理src
if (!rawSrc.startsWith('http') || !rawSrc.startsWith('https')) {
rawSrc = './game/' + rawSrc;
}
Comment thread
xiaoxustudio marked this conversation as resolved.
Outdated

const frameData: IIFrame = {
id,
src: rawSrc,
sandbox: '',
width,
height,
isActive: true,
isDestroy: false,
wait,
returnValue,
};

for (const [key, value] of Object.entries(allSandboxProperties)) {
const v = getStringArgByKey(sentence, value) ?? '';
if (v) {
frameData.sandbox += key + ' ';
}
}

webgalStore.dispatch(stageActions.addFrame(frameData));

// 如果需要等待iframe完成,则返回阻塞的perform
if (wait) {
let isCompleted = false;
// 监听iframe完成消息
const handleFrameComplete = (event: MessageEvent) => {
if (event.data.type === 'webgal-frame-complete' && event.data.frameId === id) {
Comment thread
xiaoxustudio marked this conversation as resolved.
Outdated
isCompleted = true;
// 如果有returnValue,则存储到游戏变量中
if (returnValue && event.data.returnValue !== undefined) {
webgalStore.dispatch(
stageActions.setStageVar({
key: returnValue,
value: event.data.returnValue,
}),
);
}
// 移除事件监听器
window.removeEventListener('message', handleFrameComplete);
}
};

// 添加事件监听器
window.addEventListener('message', handleFrameComplete);

return {
performName: `frame-wait-${id}`,
duration: 0,
isHoldOn: true,
stopFunction: () => {
window.removeEventListener('message', handleFrameComplete);
},
blockingNext: () => !isCompleted,
blockingAuto: () => !isCompleted,
stopTimeout: undefined,
};
}

return {
performName: 'none',
duration: 0,
isHoldOn: false,
stopFunction: () => {},
blockingNext: () => false,
blockingAuto: () => true,
stopTimeout: undefined,
};
};
34 changes: 34 additions & 0 deletions packages/webgal/src/Core/gameScripts/removeFrame.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { ISentence } from '@/Core/controller/scene/sceneInterface';
import { IPerform } from '@/Core/Modules/perform/performInterface';
import { stageActions } from '@/store/stageReducer';
import { webgalStore } from '@/store/store';

/**
* 移除框架
* @param sentence
*/
export const removeFrame = (sentence: ISentence): IPerform => {
const id = sentence.content;
if (!id) {
return {
performName: 'none',
duration: 0,
isHoldOn: false,
stopFunction: () => {},
blockingNext: () => false,
blockingAuto: () => true,
stopTimeout: undefined,
};
}
webgalStore.dispatch(stageActions.removeFrame(id));

return {
performName: 'none',
duration: 0,
isHoldOn: false,
stopFunction: () => {},
blockingNext: () => false,
blockingAuto: () => true,
stopTimeout: undefined,
};
};
4 changes: 4 additions & 0 deletions packages/webgal/src/Core/parser/sceneParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import { setTransition } from '@/Core/gameScripts/setTransition';
import { unlockBgm } from '@/Core/gameScripts/unlockBgm';
import { unlockCg } from '@/Core/gameScripts/unlockCg';
import { callSteam } from '@/Core/gameScripts/callSteam';
import { createFrame } from '@/Core/gameScripts/createFrame';
import { removeFrame } from '@/Core/gameScripts/removeFrame';
import { end } from '../gameScripts/end';
import { jumpLabel } from '../gameScripts/jumpLabel';
import { pixiInit } from '../gameScripts/pixi/pixiInit';
Expand Down Expand Up @@ -74,6 +76,8 @@ export const SCRIPT_TAG_MAP = defineScripts({
applyStyle: ScriptConfig(commandType.applyStyle, applyStyle, { next: true }),
wait: ScriptConfig(commandType.wait, wait),
callSteam: ScriptConfig(commandType.callSteam, callSteam, { next: true }),
createFrame: ScriptConfig(commandType.createFrame, createFrame),
removeFrame: ScriptConfig(commandType.removeFrame, removeFrame),
});

export const SCRIPT_CONFIG: IConfigInterface[] = Object.values(SCRIPT_TAG_MAP);
Expand Down
Loading
Loading