refactor: reorg
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
import {createEffect, createResource } from "solid-js";
|
||||
import type {OptionsResult, RuntimeResult} from "../../yarn-spinner/runtime/results";
|
||||
import {compile, parseYarn, YarnRunner} from "../../yarn-spinner";
|
||||
import {loadElementSrc, resolvePath} from "../utils/path";
|
||||
import {createStore} from "solid-js/store";
|
||||
import {RunnerOptions} from "../../yarn-spinner/runtime/runner";
|
||||
|
||||
type YarnSpinnerStore = {
|
||||
dialogueHistory: (RuntimeResult | OptionsResult['options'][0])[],
|
||||
currentOptions: OptionsResult | null,
|
||||
isEnded: boolean,
|
||||
runnerInstance: YarnRunner | null,
|
||||
}
|
||||
|
||||
export function createYarnStore(element: HTMLElement, props: RunnerOptions){
|
||||
const [store, setStore] = createStore<YarnSpinnerStore>({
|
||||
dialogueHistory: [],
|
||||
currentOptions: null,
|
||||
isEnded: false,
|
||||
runnerInstance: null
|
||||
});
|
||||
|
||||
// 获取文件路径
|
||||
const {articlePath, rawSrc} = loadElementSrc(element);
|
||||
const yarnPaths = (rawSrc || '').split(',')
|
||||
.map((s: string) => resolvePath(articlePath, s.trim()))
|
||||
.filter(Boolean);
|
||||
|
||||
// 加载 yarn 内容
|
||||
const [yarnContent] = createResource(() => yarnPaths, loadYarnFiles);
|
||||
|
||||
// 创建 runner
|
||||
const createRunner = () => {
|
||||
const content = yarnContent();
|
||||
if (!content) return null;
|
||||
|
||||
try {
|
||||
const ast = parseYarn(content);
|
||||
const program = compile(ast);
|
||||
|
||||
return new YarnRunner(program, props);
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize YarnRunner:', error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
function advance(index?: number){
|
||||
const runner = store.runnerInstance;
|
||||
if(!runner) return;
|
||||
if(index === undefined && runner.currentResult?.isDialogueEnd) return;
|
||||
if(runner.currentResult?.type === 'options'){
|
||||
if(index === undefined)return;
|
||||
const option = runner.currentResult.options[index];
|
||||
setStore('dialogueHistory', [...store.dialogueHistory, option]);
|
||||
}
|
||||
runner.advance(index);
|
||||
processRunnerOutput();
|
||||
}
|
||||
|
||||
createEffect(() => {
|
||||
if(!yarnContent()) return;
|
||||
setStore('runnerInstance', createRunner());
|
||||
requestAnimationFrame(function(){
|
||||
advance();
|
||||
});
|
||||
});
|
||||
|
||||
// 处理 runner 输出
|
||||
const processRunnerOutput = () => {
|
||||
const runner = store.runnerInstance;
|
||||
if(!runner)return;
|
||||
|
||||
const result = runner.currentResult;
|
||||
if (!result) return;
|
||||
|
||||
if(result.type === 'options'){
|
||||
setStore('currentOptions', result);
|
||||
}else{
|
||||
setStore('currentOptions', null);
|
||||
}
|
||||
|
||||
setStore('dialogueHistory', [...store.dialogueHistory, result]);
|
||||
};
|
||||
|
||||
// 重新开始
|
||||
const restart = () => {
|
||||
setStore({
|
||||
dialogueHistory: [],
|
||||
currentOptions: null,
|
||||
isEnded: false,
|
||||
runnerInstance: createRunner(),
|
||||
});
|
||||
processRunnerOutput();
|
||||
};
|
||||
|
||||
return {
|
||||
store,
|
||||
advance,
|
||||
restart,
|
||||
}
|
||||
}
|
||||
|
||||
// 缓存已加载的 yarn 文件内容
|
||||
const yarnCache = new Map<string, string>();
|
||||
|
||||
// 加载 yarn 文件内容
|
||||
async function loadYarnFile(path: string): Promise<string> {
|
||||
if (yarnCache.has(path)) {
|
||||
return yarnCache.get(path)!;
|
||||
}
|
||||
const response = await fetch(path);
|
||||
const content = await response.text();
|
||||
yarnCache.set(path, content);
|
||||
return content;
|
||||
}
|
||||
|
||||
// 加载多个 yarn 文件并拼接
|
||||
async function loadYarnFiles(paths: string[]): Promise<string> {
|
||||
const contents = await Promise.all(paths.map(path => loadYarnFile(path)));
|
||||
return contents.join('\n');
|
||||
}
|
||||
Reference in New Issue
Block a user