feat(scum): add bounded vehicle spawn adapter
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
import { configurationCatalog, stateFieldCatalog } from "./schemas.js";
|
||||
import { configurationCatalog, stateFieldCatalog, vehicleSpawnCatalog } from "./schemas.js";
|
||||
import type { SCUMFeatureWorkspace } from "./contracts.js";
|
||||
|
||||
export type ReactLike = { createElement: (...args: any[]) => any; useMemo?: <T>(factory: () => T, deps: readonly unknown[]) => T };
|
||||
export type SCUMPageContext = { serverInstanceId?: string; permissions: string[]; availability: { available: boolean; reason?: string }; featureAvailability?: Array<{ key: string; available: boolean; reason?: string }>; workspace?: SCUMFeatureWorkspace; serverVersion?: string };
|
||||
|
||||
export function renderSCUMFeaturePage(react: ReactLike, input: SCUMPageContext) {
|
||||
const e = react.createElement; const version = input.serverVersion ?? "0.9.700.90357"; const fields = input.workspace?.configFields?.length ? input.workspace.configFields : configurationCatalog(version); const scoped = Boolean(input.serverInstanceId); const canRead = scoped && input.permissions.includes("server.game-client.read"); const canCommand = scoped && input.permissions.includes("server.game-client.command"); const canMaintain = scoped && input.permissions.includes("server.game-client.maintenance");
|
||||
const e = react.createElement; const version = input.serverVersion ?? "0.9.700.90357"; const fields = input.workspace?.configFields?.length ? input.workspace.configFields : configurationCatalog(version); const vehicleCodes = vehicleSpawnCatalog(version); const scoped = Boolean(input.serverInstanceId); const canRead = scoped && input.permissions.includes("server.game-client.read"); const canCommand = scoped && input.permissions.includes("server.game-client.command"); const canMaintain = scoped && input.permissions.includes("server.game-client.maintenance");
|
||||
return e("div", { className: "console-page", "aria-label": "SCUM 插件功能页面" },
|
||||
e("section", { className: "console-panel" }, e("div", { className: "panel-header" }, e("div", null, e("h2", null, "SCUM 插件运维"), e("p", { className: "provider-id" }, "SCUM 语义、界面和适配器由插件提供;平台仅提供已授权的服务器隔离宿主。")), e("span", { className: "page-status" }, availabilityText(input.availability, scoped))),
|
||||
e("div", { className: "console-row-list" }, e("div", { className: "console-row" }, e("strong", null, "绑定服务器"), e("span", null, input.serverInstanceId ?? "未绑定")), e("div", { className: "console-row" }, e("strong", null, "配置版本目录"), e("span", null, version)), e("div", { className: "console-row" }, e("strong", null, "宿主权限"), e("span", null, input.permissions.join("、") || "无")))),
|
||||
@@ -13,6 +13,7 @@ export function renderSCUMFeaturePage(react: ReactLike, input: SCUMPageContext)
|
||||
playerPanel(e, canRead, featureAvailability(input, "player.intelligence")),
|
||||
rewardPanel(e, canRead, canCommand, featureAvailability(input, "reward.delivery")),
|
||||
statePanel(e, version, canRead, canMaintain, featureAvailability(input, "state.patch")),
|
||||
vehicleSpawnPanel(e, vehicleCodes, canCommand, featureAvailability(input, "vehicle.spawn")),
|
||||
trajectoryPanel(e, canRead, featureAvailability(input, "trajectory.collect"))
|
||||
);
|
||||
}
|
||||
@@ -21,6 +22,7 @@ function configurationPanel(e: ReactLike["createElement"], fields: readonly { ke
|
||||
function playerPanel(e: ReactLike["createElement"], canRead: boolean, availability: { available: boolean; reason?: string }) { return e("section", { className: "console-panel", "aria-label": "SCUM 玩家档案" }, e("div", { className: "panel-header" }, e("div", null, e("h2", null, "玩家、登录与风险信号"), e("p", { className: "provider-id" }, "只展示 Companion 已验证的语义事件;网络关联是按服务器不可逆计算,不上传原始网络值。")), e("button", { type: "button", className: "icon-command", disabled: !canRead || !availability.available }, "查询玩家")), e("p", { className: "page-status" }, !canRead ? "当前服务器上下文没有玩家读取权限。" : availability.available ? "等待已验证的登录或登出事件。" : availability.reason ?? "没有兼容的事件生产者。")); }
|
||||
function rewardPanel(e: ReactLike["createElement"], canRead: boolean, canCommand: boolean, availability: { available: boolean; reason?: string }) { return e("section", { className: "console-panel", "aria-label": "SCUM 礼物与通知" }, e("div", { className: "panel-header" }, e("div", null, e("h2", null, "冻结礼物版本与通知"), e("p", { className: "provider-id" }, "物品投递与通知分离;未知投递结果不会自动重试。")), e("button", { type: "button", className: "icon-command", disabled: !canCommand || !availability.available }, "申请投递")), e("p", { className: "page-status" }, !canRead ? "当前服务器上下文没有礼物读取权限。" : !canCommand ? "当前服务器上下文没有受控投递权限。" : availability.reason ?? "需要已冻结 revision、已验证玩家身份和兼容处理器。")); }
|
||||
function statePanel(e: ReactLike["createElement"], version: string, canRead: boolean, canMaintain: boolean, availability: { available: boolean; reason?: string }) { const fields = stateFieldCatalog(version); return e("section", { className: "console-panel", "aria-label": "SCUM 受控状态修改" }, e("div", { className: "panel-header" }, e("div", null, e("h2", null, "受控属性修改"), e("p", { className: "provider-id" }, "仅列出已发现版本支持的字段,执行时要求预读、安全窗口与读后确认。")), e("button", { type: "button", className: "icon-command", disabled: !canRead || !canMaintain || !availability.available }, "创建修改申请")), e("div", { className: "console-row-list" }, fields.length ? fields.map((field) => e("div", { className: "console-row", key: field.key }, e("strong", null, field.label), e("span", null, `${field.minimum}–${field.maximum}`))) : e("p", { className: "page-status" }, "当前 SCUM 版本没有已验证的状态字段。")), e("p", { className: "page-status" }, canMaintain ? availability.reason ?? "等待安全窗口验证。" : "当前服务器上下文没有维护权限。")); }
|
||||
function vehicleSpawnPanel(e: ReactLike["createElement"], vehicles: readonly { code: string; label: string }[], canCommand: boolean, availability: { available: boolean; reason?: string }) { return e("section", { className: "console-panel", "aria-label": "SCUM 受限载具生成" }, e("div", { className: "panel-header" }, e("div", null, e("h2", null, "受限载具生成"), e("p", { className: "provider-id" }, "仅可选择当前版本目录中的载具;不会显示或接收原始指令、参数或回包。")), e("button", { type: "button", className: "icon-command", disabled: !canCommand || !availability.available }, "生成载具")), e("div", { className: "console-row-list" }, vehicles.map((vehicle) => e("div", { className: "console-row", key: vehicle.code }, e("strong", null, vehicle.label), e("span", null, vehicle.code)))), e("p", { className: "page-status" }, !canCommand ? "当前服务器上下文没有受控指令权限。" : availability.available ? "仅在审批、版本和 Companion 处理器均可用时开放。" : availability.reason ?? "当前版本没有已验证的载具生成处理器。")); }
|
||||
function trajectoryPanel(e: ReactLike["createElement"], canRead: boolean, availability: { available: boolean; reason?: string }) { return e("section", { className: "console-panel", "aria-label": "SCUM 地图轨迹" }, e("div", { className: "panel-header" }, e("div", null, e("h2", null, "玩家与载具轨迹"), e("p", { className: "provider-id" }, "仅接受插件声明的服务器侧位置与上下车事件源;绝不使用 OCR、截图或桌面自动化。")), e("button", { type: "button", className: "icon-command", disabled: !canRead || !availability.available }, "读取轨迹")), e("p", { className: "page-status" }, canRead ? availability.reason ?? "当合法位置源可用时展示采样轨迹。" : "当前服务器上下文没有轨迹读取权限。")); }
|
||||
function featureAvailability(input: SCUMPageContext, key: string): { available: boolean; reason?: string } { const feature = input.featureAvailability?.find((item) => item.key === key); return feature ?? { available: false, reason: "当前服务器版本没有已验证的 Companion 处理器或事件生产者。" }; }
|
||||
function availabilityText(availability: { available: boolean; reason?: string }, scoped: boolean): string { if (!scoped) return "不可用:插件页面必须绑定服务器。"; return availability.available ? "已声明且已由 Companion 验证" : `不可用:${availability.reason ?? "没有兼容的 Companion 处理器或事件生产者"}`; }
|
||||
|
||||
Reference in New Issue
Block a user