-
-
Notifications
You must be signed in to change notification settings - Fork 354
feat: callScene supports args #1011
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -40,6 +40,7 @@ export enum commandType { | |
| applyStyle, | ||
| wait, | ||
| callSteam, // 调用Steam功能 | ||
| return, // 从被调用的场景返回 | ||
| } | ||
|
|
||
| /** | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| import { restoreScene } from './restoreScene'; | ||
| import { setGameVar } from '@/Core/gameScripts/setVar'; | ||
|
|
||
| import { WebGAL } from '@/Core/WebGAL'; | ||
|
|
||
| /** | ||
| * 从被调用的场景返回:弹出调用帧,把返回值写回调用方,再恢复调用方场景。 | ||
| * 场景栈为空(顶层场景)或场景正在写入时不做任何事。 | ||
| * @param returnValue 返回值,没有 return 语句而自然结束时为空值 | ||
| */ | ||
| export const returnFromScene = (returnValue: string | boolean | number = '') => { | ||
| // 必须在弹栈之前判定,否则 restoreScene 提前返回会丢掉这一帧 | ||
| if (WebGAL.sceneManager.lockSceneWrite) { | ||
| return; | ||
| } | ||
| const entry = WebGAL.sceneManager.popFrame(); | ||
| if (!entry) { | ||
| return; | ||
| } | ||
| if (entry.writeReturnTo) { | ||
| setGameVar({ key: entry.writeReturnTo, value: returnValue }); | ||
|
Comment on lines
+20
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a nested caller already has a local with the Useful? React with 👍 / 👎. |
||
| } | ||
| restoreScene(entry); | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,14 +1,35 @@ | ||
| import { ISentence } from '@/Core/controller/scene/sceneInterface'; | ||
| import { createNonePerform, IPerform } from '@/Core/Modules/perform/performInterface'; | ||
| import { IGameVar } from '@/Core/Modules/stage/stageInterface'; | ||
| import { callScene } from '../controller/scene/callScene'; | ||
|
|
||
| /** | ||
| * 还原参数值的类型。参数经过变量插值后恒为字符串,这里按解析器的规则重新判定。 | ||
| * @see packages/parser/src/scriptParser/argsParser.ts | ||
| */ | ||
| const restoreArgValueType = (value: string | boolean | number) => { | ||
| if (typeof value !== 'string') return value; | ||
| if (value === 'true' || value === 'false') return value === 'true'; | ||
| if (!isNaN(Number(value))) return Number(value); | ||
| return value; | ||
| }; | ||
|
|
||
| /** | ||
| * 调用一个场景,在场景结束后回到调用这个场景的父场景。 | ||
| * @param sentence | ||
| */ | ||
| export const callSceneScript = (sentence: ISentence): IPerform => { | ||
| const sceneNameArray: Array<string> = sentence.content.split('/'); | ||
| const sceneName = sceneNameArray[sceneNameArray.length - 1]; | ||
| callScene(sentence.content, sceneName); | ||
| // 所有参数原样成为被调用场景的局部变量,包括 when、next 等通用参数,子场景用不用随意 | ||
| const locals: IGameVar = {}; | ||
| let writeReturnTo: string | undefined; | ||
| sentence.args.forEach(({ key, value }) => { | ||
| locals[key] = restoreArgValueType(value); | ||
| if (key === 'writeReturnTo' && typeof value === 'string') { | ||
| writeReturnTo = value; | ||
| } | ||
| }); | ||
| callScene(sentence.content, sceneName, locals, writeReturnTo); | ||
| return createNonePerform({ isHoldOn: true }); | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import { ISentence } from '@/Core/controller/scene/sceneInterface'; | ||
| import { createNonePerform, IPerform } from '@/Core/Modules/perform/performInterface'; | ||
| import { returnFromScene } from '@/Core/controller/scene/returnFromScene'; | ||
| import { resolveSetVarValue } from './setVar'; | ||
|
|
||
| /** | ||
| * 从被调用的场景返回,可携带返回值。返回值在被调用场景的作用域内求值。 | ||
| * @param sentence | ||
| */ | ||
| export const returnScript = (sentence: ISentence): IPerform => { | ||
| // 不写冒号时(`return;`)解析器会把整条命令留在 content 里,此时视为无返回值 | ||
| const valExp = sentence.content === sentence.commandRaw ? '' : sentence.content; | ||
| returnFromScene(resolveSetVarValue(valExp)); | ||
| return createNonePerform({ isHoldOn: true }); | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,6 +11,7 @@ import get from 'lodash/get'; | |
| import random from 'lodash/random'; | ||
| import { getBooleanArgByKey } from '../util/getSentenceArg'; | ||
| import { stageStateManager } from '@/Core/Modules/stage/stageStateManager'; | ||
| import { WebGAL } from '@/Core/WebGAL'; | ||
|
|
||
| interface ISetGameVarFromExpressionPayload { | ||
| key: string; | ||
|
|
@@ -19,6 +20,17 @@ interface ISetGameVarFromExpressionPayload { | |
| persistGlobal?: boolean; | ||
| } | ||
|
|
||
| /** | ||
| * 写入游戏变量。setVar 与场景返回值共用这一条写入路径。 | ||
| */ | ||
| export const setGameVar = (payload: ISetGameVar, isGlobal = false) => { | ||
| if (isGlobal) { | ||
| webgalStore.dispatch(setScriptManagedGlobalVar(payload)); | ||
| } else { | ||
| stageStateManager.setStageVar(payload); | ||
| } | ||
| }; | ||
|
|
||
| /** | ||
| * 设置变量表达式。 | ||
| */ | ||
|
|
@@ -28,19 +40,11 @@ export const setGameVarFromExpression = ({ | |
| isGlobal = false, | ||
| persistGlobal = true, | ||
| }: ISetGameVarFromExpressionPayload) => { | ||
| const setGameVar = (payload: ISetGameVar) => { | ||
| if (isGlobal) { | ||
| webgalStore.dispatch(setScriptManagedGlobalVar(payload)); | ||
| } else { | ||
| stageStateManager.setStageVar(payload); | ||
| } | ||
| }; | ||
|
|
||
| const normalizedKey = key.trim(); | ||
| if (!normalizedKey) { | ||
| return; | ||
| } | ||
| setGameVar({ key: normalizedKey, value: resolveSetVarValue(value) }); | ||
| setGameVar({ key: normalizedKey, value: resolveSetVarValue(value) }, isGlobal); | ||
| if (isGlobal) { | ||
| logger.debug('设置全局变量:', { | ||
| key: normalizedKey, | ||
|
|
@@ -131,10 +135,14 @@ function EvaluateExpression(val: string) { | |
| */ | ||
| export function getValueFromState(key: string) { | ||
| let ret: any; | ||
| const locals = WebGAL.sceneManager.sceneData.currentLocals; | ||
| const stage = stageStateManager.getCalculationStageState(); | ||
| const userData = webgalStore.getState().userData; | ||
| const _Merge = { stage, userData }; // 不要直接合并到一起,防止可能的键冲突 | ||
| if (stage.GameVar.hasOwnProperty(key)) { | ||
| // 查找链:当前帧局部变量 -> 舞台变量 -> 全局变量 | ||
| if (locals.hasOwnProperty(key)) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Because every argument name is accepted as a local, a call such as Useful? React with 👍 / 👎. |
||
| ret = locals[key]; | ||
| } else if (stage.GameVar.hasOwnProperty(key)) { | ||
| ret = stage.GameVar[key]; | ||
| } else if (userData.globalGameVar.hasOwnProperty(key)) { | ||
| ret = userData.globalGameVar[key]; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When
sceneFetcherrejects—for example because a referenced scene is missing or not a.txtfile—pushFramehas already replacedcurrentLocals, but the catch handler only logs the error. The caller therefore resumes with the callee's arguments as its locals, which can shadow its variables and be persisted in later saves; pop the newly pushed frame in the failure path before unlocking.Useful? React with 👍 / 👎.