import type { ContentCatalog, ContentWorkspaceView, TriggerCatalog, TriggerDefinition, TriggerExpression, TriggerStatement, TriggerWorkspace } from '../src/types';
export const timestamp = '2026-09-13T10:00:00Z';
const id = () => crypto.randomUUID();
const literal = (value: unknown, valueType = 'string'): TriggerExpression => ({
nodeId: id(), kind: 'LITERAL', valueType, literal: value, name: '', arguments: [],
});
const reference = (name: string, valueType: string): TriggerExpression => ({ nodeId: id(), kind: 'REFERENCE', valueType, name, arguments: [] });
const statement = (value: Partial<TriggerStatement>): TriggerStatement => ({ nodeId: id(), kind: 'ACTION', name: '', inputs: {}, statements: [], elseStatements: [], cases: [], ...value });
const rich = '@xfesm-rich:v1:' + JSON.stringify({ version: 1, sender: { visible: true, text: '冒险者大厅', color: '#55ff55' },
segments: [{ text: '欢迎 ', color: '#dddddd' }, { text: '{player.name}', color: '#ffff55', bold: true },
{ text: '!新旅程即将开始。', color: '#dddddd' }] });
const welcome: TriggerDefinition = {
id: id(), groupId: 'preview-welcome', name: '玩家首次进入 · 欢迎与奖励',
description: '本地样式预览:双击节点打开真实编辑弹窗;保存仅修改浏览器内存。', enabled: true,
mode: 'visual', event: { type: 'player.join', configuration: {} }, conditionMode: 'all', conditions: [],
actions: [{ type: 'broadcast', parameters: { message: rich } }], script: '', revision: 4,
createdBy: 'preview-owner', createdAt: timestamp, updatedAt: timestamp, migrated: false,
schemaVersion: 2, events: [{ nodeId: id(), type: 'player.join', configuration: {} }],
declarations: [{ nodeId: id(), name: 'welcomeCount', valueType: 'integer', initialValue: literal(0, 'integer'),
visibility: 'trigger', storage: 'player', lifetime: 'PERSISTENT' }], functions: [],
statements: [statement({ kind: 'IF', expression: { nodeId: id(), kind: 'BINARY', name: '==', valueType: 'bool',
arguments: [reference('event.player.firstJoin', 'bool'), literal(true, 'bool')] },
statements: [statement({ name: 'broadcast', inputs: { message: literal(rich) } }),
statement({ kind: 'IF', expression: { nodeId: id(), kind: 'BINARY', name: '<', valueType: 'bool',
arguments: [reference('var.welcomeCount', 'integer'), literal(3, 'integer')] },
statements: [statement({ name: 'send_player', inputs: { message: literal('右键向导罗盘,开启你的冒险任务。') } })] }),
statement({ kind: 'SET', name: 'welcomeCount', expression: { nodeId: id(), kind: 'BINARY', name: '+', valueType: 'integer',
arguments: [reference('var.welcomeCount', 'integer'), literal(1, 'integer')] } })],
elseStatements: [statement({ name: 'actionbar', inputs: { message: literal('欢迎回来,{player.name}!') } })] })],
};
export const triggerWorkspace: TriggerWorkspace = { totalTriggers: 3, groups: [
{ id: 'preview-welcome', name: '玩家体验', description: '欢迎、规则和奖励', enabled: true, revision: 2,
createdBy: 'preview-owner', createdAt: timestamp, updatedAt: timestamp, migrated: false, triggers: [welcome,
{ ...structuredClone(welcome), id: id(), name: '大厅规则提醒', statements: [statement({ name: 'send_player', inputs: { message: literal('请友善交流,保护共同的世界。') } })] }] },
{ id: 'preview-world', name: '世界与玩法', description: '区域事件、计时器', enabled: true, revision: 1,
createdBy: 'preview-owner', createdAt: timestamp, updatedAt: timestamp, migrated: false,
triggers: [{ ...structuredClone(welcome), id: id(), groupId: 'preview-world', name: '每日冒险公告' }] },
] };
const descriptor = (key: string, kind: 'EVENT' | 'ACTION' | 'TYPE', name: string, description: string, parameters: string[] = []): NonNullable<TriggerCatalog['descriptors']>[number] => ({
id: key, kind, displayName: name, description, parameters: parameters.map((name) => ({ name, valueType: 'expression<string>', required: true, defaultValue: '' })),
returnType: kind === 'TYPE' ? key : 'void', purity: kind === 'ACTION' ? 'SIDE_EFFECT' : 'PURE', threadAffinity: kind === 'TYPE' ? 'BACKGROUND' : 'SERVER',
risk: 'SAFE', supportedPlatforms: ['*'], applicableEvents: ['*'], metadata: { displayNameZh: name, descriptionZh: description },
});
export const triggerCatalog: TriggerCatalog = {
schemaVersion: 2, catalogRevision: 20260913, defaultMessageSender: '冒险者大厅',
events: ['player.join', 'player.leave', 'region.enter', 'schedule.daily'], operators: ['eq', 'neq', 'gt', 'lt', 'contains', 'true', 'false'],
actions: ['broadcast', 'send_player', 'actionbar', 'title', 'open_menu', 'log'],
actionParameters: { broadcast: ['message'], send_player: ['message'], actionbar: ['message'], title: ['title', 'subtitle'], open_menu: ['menuId'], log: ['message', 'level'] },
budgets: { nodes: 4096, nestingDepth: 32, callDepth: 16, loopIterations: 10000, instructions: 100000 },
triggerVariableTypes: ['string', 'integer', 'bool', 'float', 'position'], variableLifetimes: ['session', 'ttl', 'persistent'],
variableStorageScopes: ['trigger', 'server', 'player'], variables: [
{ key: 'player.name', nameZh: '玩家名称', nameEn: 'Player name', descriptionZh: '触发事件的玩家名称。', descriptionEn: 'Event player name.', category: 'player', scopes: ['player.*'], events: ['player.*'], example: '{player.name}', sampleValue: 'Alex', type: 'string', templateAllowed: true, conditionAllowed: true },
{ key: 'player.firstJoin', nameZh: '首次进入服务器', nameEn: 'First join', descriptionZh: '玩家是否首次进入服务器。', descriptionEn: 'Whether this is the first join.', category: 'player', scopes: ['player.join'], events: ['player.join'], example: '{player.firstJoin}', sampleValue: 'true', type: 'boolean', templateAllowed: true, conditionAllowed: true },
], descriptors: [descriptor('player.join', 'EVENT', '玩家进入服务器', '玩家连接并加入世界时执行这个程序。'),
descriptor('player.leave', 'EVENT', '玩家离开服务器', '玩家断开连接时触发。'),
descriptor('broadcast', 'ACTION', '全服广播', '向所有在线玩家发送富文本消息。', ['message']),
descriptor('send_player', 'ACTION', '向事件玩家发送消息', '发送仅事件玩家可见的聊天消息。', ['message']),
descriptor('actionbar', 'ACTION', '显示动作栏', '在玩家快捷栏上方显示提示。', ['message']),
descriptor('title', 'ACTION', '显示标题', '显示彩色主标题和副标题。', ['title', 'subtitle']),
descriptor('open_menu', 'ACTION', '打开菜单', '为玩家打开指定菜单。', ['menuId']),
descriptor('log', 'ACTION', '记录日志', '写入服务器日志。', ['message', 'level']),
descriptor('string', 'TYPE', '文本', '一段文字,可用于消息或表达式。'),
descriptor('integer', 'TYPE', '整数', '没有小数部分的数值。'), descriptor('bool', 'TYPE', '布尔值', '真或假。')],
};
const property = (key: string, nameZh: string, type: 'int' | 'number' | 'resource' | 'menu_ref' = 'resource', defaultValue = '') => ({ key, nameZh, nameEn: key, descriptionZh: `${nameZh},此处为本地预览数据。`, descriptionEn: 'Local preview data.', type, defaultValue, min: null, max: null, options: [], requiresRestart: true });
const seat = { id: 'xfesmcontent:oak_seat', kind: 'BLOCK' as const, name: '橡木休闲椅', description: '右键坐下,潜行离开。', archetype: 'solid',
properties: { hardness: '2.5', texture: 'minecraft:block/oak_planks' }, behaviors: [{ id: 'sit', event: 'right_click', action: 'sit', parameters: { height: '0.5' }, cooldownTicks: 10, cancelVanilla: true }] };
export const contentCatalog: ContentCatalog = { schemaVersion: 1, archetypes: [
{ id: 'generic', kind: 'ITEM', nameZh: '普通物品', nameEn: 'Item', descriptionZh: '游戏中的自定义物品和工具。', descriptionEn: 'Custom item.', properties: [property('max_stack_size', '堆叠上限', 'int', '64'), property('texture', '贴图')] },
{ id: 'solid', kind: 'BLOCK', nameZh: '实体方块', nameEn: 'Block', descriptionZh: '可以放置并交互的方块。', descriptionEn: 'Placeable block.', properties: [property('hardness', '硬度', 'number', '2.5'), property('texture', '贴图')] },
{ id: 'cow', kind: 'ENTITY', nameZh: '牛', nameEn: 'Cow', descriptionZh: '基于牛的自定义生物。', descriptionEn: 'Custom cow.', properties: [property('max_health', '最大生命值', 'number', '20')] },
], events: [{ id: 'right_click', nameZh: '玩家右键', nameEn: 'Right click', descriptionZh: '玩家使用或交互时触发。', descriptionEn: 'On interaction.', kinds: ['ITEM', 'BLOCK', 'ENTITY'], archetypes: [], cancellable: true }],
actions: [{ id: 'sit', nameZh: '坐在方块上', nameEn: 'Sit', descriptionZh: '在交互方块上创建临时座位。', descriptionEn: 'Sit on block.', events: ['right_click'], kinds: ['BLOCK'], parameters: [property('height', '座位高度', 'number', '0.5')] },
{ id: 'open_menu', nameZh: '打开菜单', nameEn: 'Open menu', descriptionZh: '打开大厅菜单。', descriptionEn: 'Open a menu.', events: ['right_click'], kinds: ['ITEM'], parameters: [property('menu_id', '目标菜单', 'menu_ref')] }],
templates: [{ id: 'seat', nameZh: '可坐座椅', nameEn: 'Seat', descriptionZh: '创建可以坐下的方块。', descriptionEn: 'A seat block.', definition: seat }],
};
export const contentWorkspace: ContentWorkspaceView = { workspace: { schemaVersion: 1, revision: 4, enabled: true,
definitions: [seat, { id: 'xfesmcontent:guide', kind: 'ITEM', name: '向导罗盘', description: '右键打开大厅菜单。', archetype: 'generic',
properties: { max_stack_size: '1', texture: 'minecraft:item/compass' }, behaviors: [] }], updatedAt: timestamp, updatedBy: 'preview-owner' },
publishedRevision: 4, loadedRevision: 4, restartRequired: false, clientRequired: true };
import type { ContentCatalog, ContentWorkspaceView, TriggerCatalog, TriggerDefinition, TriggerExpression, TriggerStatement, TriggerWorkspace } from '../src/types';
export const timestamp = '2026-09-13T10:00:00Z';
const id = () => crypto.randomUUID();
const literal = (value: unknown, valueType = 'string'): TriggerExpression => ({
nodeId: id(), kind: 'LITERAL', valueType, literal: value, name: '', arguments: [],
});
const reference = (name: string, valueType: string): TriggerExpression => ({ nodeId: id(), kind: 'REFERENCE', valueType, name, arguments: [] });
const statement = (value: Partial<TriggerStatement>): TriggerStatement => ({ nodeId: id(), kind: 'ACTION', name: '', inputs: {}, statements: [], elseStatements: [], cases: [], ...value });
const rich = '@xfesm-rich:v1:' + JSON.stringify({ version: 1, sender: { visible: true, text: '冒险者大厅', color: '#55ff55' },
segments: [{ text: '欢迎 ', color: '#dddddd' }, { text: '{player.name}', color: '#ffff55', bold: true },
{ text: '!新旅程即将开始。', color: '#dddddd' }] });
const welcome: TriggerDefinition = {
id: id(), groupId: 'preview-welcome', name: '玩家首次进入 · 欢迎与奖励',
description: '本地样式预览:双击节点打开真实编辑弹窗;保存仅修改浏览器内存。', enabled: true,
mode: 'visual', event: { type: 'player.join', configuration: {} }, conditionMode: 'all', conditions: [],
actions: [{ type: 'broadcast', parameters: { message: rich } }], script: '', revision: 4,
createdBy: 'preview-owner', createdAt: timestamp, updatedAt: timestamp, migrated: false,
schemaVersion: 2, events: [{ nodeId: id(), type: 'player.join', configuration: {} }],
declarations: [{ nodeId: id(), name: 'welcomeCount', valueType: 'integer', initialValue: literal(0, 'integer'),
visibility: 'trigger', storage: 'player', lifetime: 'PERSISTENT' }], functions: [],
statements: [statement({ kind: 'IF', expression: { nodeId: id(), kind: 'BINARY', name: '==', valueType: 'bool',
arguments: [reference('event.player.firstJoin', 'bool'), literal(true, 'bool')] },
statements: [statement({ name: 'broadcast', inputs: { message: literal(rich) } }),
statement({ kind: 'IF', expression: { nodeId: id(), kind: 'BINARY', name: '<', valueType: 'bool',
arguments: [reference('var.welcomeCount', 'integer'), literal(3, 'integer')] },
statements: [statement({ name: 'send_player', inputs: { message: literal('右键向导罗盘,开启你的冒险任务。') } })] }),
statement({ kind: 'SET', name: 'welcomeCount', expression: { nodeId: id(), kind: 'BINARY', name: '+', valueType: 'integer',
arguments: [reference('var.welcomeCount', 'integer'), literal(1, 'integer')] } })],
elseStatements: [statement({ name: 'actionbar', inputs: { message: literal('欢迎回来,{player.name}!') } })] })],
};
export const triggerWorkspace: TriggerWorkspace = { totalTriggers: 3, groups: [
{ id: 'preview-welcome', name: '玩家体验', description: '欢迎、规则和奖励', enabled: true, revision: 2,
createdBy: 'preview-owner', createdAt: timestamp, updatedAt: timestamp, migrated: false, triggers: [welcome,
{ ...structuredClone(welcome), id: id(), name: '大厅规则提醒', statements: [statement({ name: 'send_player', inputs: { message: literal('请友善交流,保护共同的世界。') } })] }] },
{ id: 'preview-world', name: '世界与玩法', description: '区域事件、计时器', enabled: true, revision: 1,
createdBy: 'preview-owner', createdAt: timestamp, updatedAt: timestamp, migrated: false,
triggers: [{ ...structuredClone(welcome), id: id(), groupId: 'preview-world', name: '每日冒险公告' }] },
] };
const descriptor = (key: string, kind: 'EVENT' | 'ACTION' | 'TYPE', name: string, description: string, parameters: string[] = []): NonNullable<TriggerCatalog['descriptors']>[number] => ({
id: key, kind, displayName: name, description, parameters: parameters.map((name) => ({ name, valueType: 'expression<string>', required: true, defaultValue: '' })),
returnType: kind === 'TYPE' ? key : 'void', purity: kind === 'ACTION' ? 'SIDE_EFFECT' : 'PURE', threadAffinity: kind === 'TYPE' ? 'BACKGROUND' : 'SERVER',
risk: 'SAFE', supportedPlatforms: ['*'], applicableEvents: ['*'], metadata: { displayNameZh: name, descriptionZh: description },
});
export const triggerCatalog: TriggerCatalog = {
schemaVersion: 2, catalogRevision: 20260913, defaultMessageSender: '冒险者大厅',
events: ['player.join', 'player.leave', 'region.enter', 'schedule.daily'], operators: ['eq', 'neq', 'gt', 'lt', 'contains', 'true', 'false'],
actions: ['broadcast', 'send_player', 'actionbar', 'title', 'open_menu', 'log'],
actionParameters: { broadcast: ['message'], send_player: ['message'], actionbar: ['message'], title: ['title', 'subtitle'], open_menu: ['menuId'], log: ['message', 'level'] },
budgets: { nodes: 4096, nestingDepth: 32, callDepth: 16, loopIterations: 10000, instructions: 100000 },
triggerVariableTypes: ['string', 'integer', 'bool', 'float', 'position'], variableLifetimes: ['session', 'ttl', 'persistent'],
variableStorageScopes: ['trigger', 'server', 'player'], variables: [
{ key: 'player.name', nameZh: '玩家名称', nameEn: 'Player name', descriptionZh: '触发事件的玩家名称。', descriptionEn: 'Event player name.', category: 'player', scopes: ['player.*'], events: ['player.*'], example: '{player.name}', sampleValue: 'Alex', type: 'string', templateAllowed: true, conditionAllowed: true },
{ key: 'player.firstJoin', nameZh: '首次进入服务器', nameEn: 'First join', descriptionZh: '玩家是否首次进入服务器。', descriptionEn: 'Whether this is the first join.', category: 'player', scopes: ['player.join'], events: ['player.join'], example: '{player.firstJoin}', sampleValue: 'true', type: 'boolean', templateAllowed: true, conditionAllowed: true },
], descriptors: [descriptor('player.join', 'EVENT', '玩家进入服务器', '玩家连接并加入世界时执行这个程序。'),
descriptor('player.leave', 'EVENT', '玩家离开服务器', '玩家断开连接时触发。'),
descriptor('broadcast', 'ACTION', '全服广播', '向所有在线玩家发送富文本消息。', ['message']),
descriptor('send_player', 'ACTION', '向事件玩家发送消息', '发送仅事件玩家可见的聊天消息。', ['message']),
descriptor('actionbar', 'ACTION', '显示动作栏', '在玩家快捷栏上方显示提示。', ['message']),
descriptor('title', 'ACTION', '显示标题', '显示彩色主标题和副标题。', ['title', 'subtitle']),
descriptor('open_menu', 'ACTION', '打开菜单', '为玩家打开指定菜单。', ['menuId']),
descriptor('log', 'ACTION', '记录日志', '写入服务器日志。', ['message', 'level']),
descriptor('string', 'TYPE', '文本', '一段文字,可用于消息或表达式。'),
descriptor('integer', 'TYPE', '整数', '没有小数部分的数值。'), descriptor('bool', 'TYPE', '布尔值', '真或假。')],
};
const property = (key: string, nameZh: string, type: 'int' | 'number' | 'resource' | 'menu_ref' = 'resource', defaultValue = '') => ({ key, nameZh, nameEn: key, descriptionZh: `${nameZh},此处为本地预览数据。`, descriptionEn: 'Local preview data.', type, defaultValue, min: null, max: null, options: [], requiresRestart: true });
const seat = { id: 'xfesmcontent:oak_seat', kind: 'BLOCK' as const, name: '橡木休闲椅', description: '右键坐下,潜行离开。', archetype: 'solid',
properties: { hardness: '2.5', texture: 'minecraft:block/oak_planks' }, behaviors: [{ id: 'sit', event: 'right_click', action: 'sit', parameters: { height: '0.5' }, cooldownTicks: 10, cancelVanilla: true }] };
export const contentCatalog: ContentCatalog = { schemaVersion: 1, archetypes: [
{ id: 'generic', kind: 'ITEM', nameZh: '普通物品', nameEn: 'Item', descriptionZh: '游戏中的自定义物品和工具。', descriptionEn: 'Custom item.', properties: [property('max_stack_size', '堆叠上限', 'int', '64'), property('texture', '贴图')] },
{ id: 'solid', kind: 'BLOCK', nameZh: '实体方块', nameEn: 'Block', descriptionZh: '可以放置并交互的方块。', descriptionEn: 'Placeable block.', properties: [property('hardness', '硬度', 'number', '2.5'), property('texture', '贴图')] },
{ id: 'cow', kind: 'ENTITY', nameZh: '牛', nameEn: 'Cow', descriptionZh: '基于牛的自定义生物。', descriptionEn: 'Custom cow.', properties: [property('max_health', '最大生命值', 'number', '20')] },
], events: [{ id: 'right_click', nameZh: '玩家右键', nameEn: 'Right click', descriptionZh: '玩家使用或交互时触发。', descriptionEn: 'On interaction.', kinds: ['ITEM', 'BLOCK', 'ENTITY'], archetypes: [], cancellable: true }],
actions: [{ id: 'sit', nameZh: '坐在方块上', nameEn: 'Sit', descriptionZh: '在交互方块上创建临时座位。', descriptionEn: 'Sit on block.', events: ['right_click'], kinds: ['BLOCK'], parameters: [property('height', '座位高度', 'number', '0.5')] },
{ id: 'open_menu', nameZh: '打开菜单', nameEn: 'Open menu', descriptionZh: '打开大厅菜单。', descriptionEn: 'Open a menu.', events: ['right_click'], kinds: ['ITEM'], parameters: [property('menu_id', '目标菜单', 'menu_ref')] }],
templates: [{ id: 'seat', nameZh: '可坐座椅', nameEn: 'Seat', descriptionZh: '创建可以坐下的方块。', descriptionEn: 'A seat block.', definition: seat }],
};
export const contentWorkspace: ContentWorkspaceView = { workspace: { schemaVersion: 1, revision: 4, enabled: true,
definitions: [seat, { id: 'xfesmcontent:guide', kind: 'ITEM', name: '向导罗盘', description: '右键打开大厅菜单。', archetype: 'generic',
properties: { max_stack_size: '1', texture: 'minecraft:item/compass' }, behaviors: [] }], updatedAt: timestamp, updatedBy: 'preview-owner' },
publishedRevision: 4, loadedRevision: 4, restartRequired: false, clientRequired: true };