45 lines
11 KiB
TypeScript
45 lines
11 KiB
TypeScript
import type { SCUMConfigField, SCUMConfigPatch, SCUMFeatureAvailability, SCUMStateField, SCUMVehicleSpawn, SCUMVehicleSpawnOption } from "./contracts.js";
|
|
|
|
// These are safe fallback plugin catalogs. Plugin-owned declarations may narrow
|
|
// them per server, but a game version never enables or disables a feature.
|
|
export const configurationCatalog: readonly SCUMConfigField[] = [
|
|
{ key: "server-name", fileKey: "scum-server-settings", configKey: "scum.ServerName", label: "服务器名称", description: "显示在服务器浏览器与玩家连接界面。", control: "text", defaultValue: "SCUM Server", restartImpact: "restart-required" },
|
|
{ key: "game-port", fileKey: "scum-server-settings", configKey: "GamePort", label: "游戏端口", description: "玩家连接所使用的游戏端口。", control: "port", minimum: 1, maximum: 65535, defaultValue: "7779", restartImpact: "restart-required" },
|
|
{ key: "query-port", fileKey: "scum-server-settings", configKey: "QueryPort", label: "查询端口", description: "服务器查询和状态发现所使用的端口。", control: "port", minimum: 1, maximum: 65535, defaultValue: "27015", restartImpact: "restart-required" },
|
|
{ key: "max-players", fileKey: "scum-server-settings", configKey: "scum.MaxPlayers", label: "最大玩家数", description: "允许同时进入服务器的玩家上限。", control: "number", minimum: 1, maximum: 128, defaultValue: "128", restartImpact: "restart-required" },
|
|
{ key: "welcome-message", fileKey: "scum-server-settings", configKey: "scum.WelcomeMessage", label: "欢迎消息", description: "玩家登录后显示的欢迎消息。", control: "text", defaultValue: "", restartImpact: "none" },
|
|
{ key: "server-description", fileKey: "scum-server-settings", configKey: "scum.ServerDescription", label: "服务器描述", description: "显示在服务器列表中的详细描述。", control: "text", defaultValue: "", restartImpact: "restart-required" },
|
|
{ key: "server-password", fileKey: "scum-server-settings", configKey: "scum.ServerPassword", label: "服务器密码", description: "留空表示不设置连接密码。", control: "text", defaultValue: "", restartImpact: "restart-required" },
|
|
{ key: "server-playstyle", fileKey: "scum-server-settings", configKey: "scum.ServerPlaystyle", label: "服务器玩法", description: "服务器使用的玩法类型,例如 PVE 或 PVP。", control: "text", defaultValue: "PVE", restartImpact: "restart-required" },
|
|
{ key: "message-of-the-day", fileKey: "scum-server-settings", configKey: "scum.MessageOfTheDay", label: "每日公告", description: "玩家进入服务器后看到的每日公告。", control: "text", defaultValue: "", restartImpact: "none" },
|
|
{ key: "allow-first-person", fileKey: "scum-server-settings", configKey: "scum.AllowFirstPerson", label: "允许第一人称", description: "允许玩家使用第一人称视角。", control: "boolean", defaultValue: "True", restartImpact: "restart-required" },
|
|
{ key: "allow-third-person", fileKey: "scum-server-settings", configKey: "scum.AllowThirdPerson", label: "允许第三人称", description: "允许玩家使用第三人称视角。", control: "boolean", defaultValue: "True", restartImpact: "restart-required" },
|
|
{ key: "allow-global-chat", fileKey: "scum-server-settings", configKey: "scum.AllowGlobalChat", label: "允许公频聊天", description: "允许玩家使用公频聊天。", control: "boolean", defaultValue: "True", restartImpact: "none" },
|
|
{ key: "disable-base-building", fileKey: "scum-server-settings", configKey: "scum.DisableBaseBuilding", label: "禁用建家", description: "是否完全禁止玩家建造基地。", control: "boolean", defaultValue: "False", restartImpact: "restart-required" },
|
|
{ key: "allow-map-screen", fileKey: "scum-server-settings", configKey: "scum.AllowMapScreen", label: "允许地图", description: "是否允许玩家打开地图。", control: "boolean", defaultValue: "True", restartImpact: "none" },
|
|
{ key: "allow-kill-claiming", fileKey: "scum-server-settings", configKey: "scum.AllowKillClaiming", label: "允许领取击杀", description: "是否允许玩家领取击杀奖励。", control: "boolean", defaultValue: "True", restartImpact: "none" },
|
|
{ key: "allow-coma", fileKey: "scum-server-settings", configKey: "scum.AllowComa", label: "允许昏迷", description: "是否启用昏迷机制。", control: "boolean", defaultValue: "True", restartImpact: "restart-required" },
|
|
{ key: "allow-mines-and-traps", fileKey: "scum-server-settings", configKey: "scum.AllowMinesAndTraps", label: "允许地雷和陷阱", description: "是否允许使用地雷和陷阱。", control: "boolean", defaultValue: "False", restartImpact: "restart-required" },
|
|
{ key: "allow-events", fileKey: "scum-server-settings", configKey: "scum.AllowEvents", label: "允许服务器事件", description: "是否启用服务器事件。", control: "boolean", defaultValue: "True", restartImpact: "restart-required" },
|
|
{ key: "logout-timer", fileKey: "scum-server-settings", configKey: "scum.LogoutTimer", label: "下线倒计时", description: "玩家下线前的倒计时秒数。", control: "number", minimum: 0, maximum: 3600, defaultValue: "60", restartImpact: "restart-required" },
|
|
{ key: "fame-gain-multiplier", fileKey: "scum-server-settings", configKey: "scum.FameGainMultiplier", label: "声望获取倍率", description: "玩家获得声望的倍率。", control: "number", minimum: 0, maximum: 100, defaultValue: "1", restartImpact: "none" },
|
|
{ key: "max-allowed-characters", fileKey: "scum-server-settings", configKey: "scum.MaxAllowedCharacters", label: "世界角色上限", description: "世界中同时存在的角色数量上限。", control: "number", minimum: -1, maximum: 10000, defaultValue: "500", restartImpact: "restart-required" },
|
|
{ key: "max-allowed-zombies", fileKey: "scum-server-settings", configKey: "scum.MaxAllowedZombies", label: "僵尸上限", description: "世界中同时存在的僵尸数量上限。", control: "number", minimum: -1, maximum: 10000, defaultValue: "300", restartImpact: "restart-required" },
|
|
{ key: "max-allowed-animals", fileKey: "scum-server-settings", configKey: "scum.MaxAllowedAnimals", label: "动物上限", description: "世界中同时存在的动物数量上限。", control: "number", minimum: -1, maximum: 10000, defaultValue: "-1", restartImpact: "restart-required" },
|
|
{ key: "exterior-zombie-amount", fileKey: "scum-server-settings", configKey: "scum.ExteriorZombieAmountModifier", label: "室外僵尸倍率", description: "室外僵尸数量倍率。", control: "number", minimum: 0, maximum: 100, defaultValue: "3.9", restartImpact: "restart-required" },
|
|
{ key: "interior-zombie-amount", fileKey: "scum-server-settings", configKey: "scum.InteriorZombieAmountModifier", label: "室内僵尸倍率", description: "室内僵尸数量倍率。", control: "number", minimum: 0, maximum: 100, defaultValue: "2.8", restartImpact: "restart-required" },
|
|
{ key: "fuel-drain-multiplier", fileKey: "scum-server-settings", configKey: "scum.FuelDrainFromEngineMultiplier", label: "车辆耗油倍率", description: "车辆发动机燃油消耗倍率。", control: "number", minimum: 0, maximum: 100, defaultValue: "1", restartImpact: "none" },
|
|
{ key: "vehicle-inactivity-time", fileKey: "scum-server-settings", configKey: "scum.MaximumTimeOfVehicleInactivity", label: "车辆不活跃时间", description: "车辆不活跃后被处理的时间。", control: "text", defaultValue: "168:10:00", restartImpact: "restart-required" },
|
|
{ key: "log-vehicle-destroyed", fileKey: "scum-server-settings", configKey: "scum.LogVehicleDestroyed", label: "记录车辆摧毁", description: "是否记录车辆被摧毁事件。", control: "boolean", defaultValue: "True", restartImpact: "none" },
|
|
{ key: "raid-protection-type", fileKey: "scum-server-settings", configKey: "scum.RaidProtectionType", label: "抄家保护类型", description: "服务器抄家保护规则类型。", control: "number", minimum: 0, maximum: 10, defaultValue: "3", restartImpact: "restart-required" },
|
|
{ key: "quests-enabled", fileKey: "scum-server-settings", configKey: "scum.QuestsEnabled", label: "启用任务", description: "是否启用商人任务系统。", control: "boolean", defaultValue: "True", restartImpact: "none" },
|
|
{ key: "new-player-protection", fileKey: "scum-server-settings", configKey: "scum.EnableNewPlayerProtection", label: "新人保护", description: "是否启用新人保护。", control: "boolean", defaultValue: "True", restartImpact: "restart-required" }
|
|
];
|
|
export const vehicleSpawnCatalog: readonly SCUMVehicleSpawnOption[] = [{ code: "BPC_Laika_C", label: "Laika" }, { code: "BPC_WolfsWagen_C", label: "WolfsWagen" }];
|
|
export const stateFieldCatalog: readonly Omit<SCUMStateField, "value" | "editable" | "reason">[] = [{ key: "skills.running", label: "跑步技能", minimum: 0, maximum: 1000000 }, { key: "attributes.strength", label: "力量属性", minimum: 1, maximum: 8 }, { key: "attributes.stamina", label: "体力", minimum: 0, maximum: 100000 }, { key: "attributes.dexterity", label: "敏捷", minimum: 0, maximum: 100000 }, { key: "attributes.intelligence", label: "智力", minimum: 0, maximum: 100000 }];
|
|
export function supportsStateField(field: string): boolean { return /^[A-Za-z0-9_.:-]{1,120}$/.test(field); }
|
|
export function featureUnavailable(reason: string): SCUMFeatureAvailability { return { feature: "configuration", available: false, reason }; }
|
|
export function validateConfigPatch(patch: SCUMConfigPatch): string | null { if (!patch.idempotencyKey.trim() || !patch.reason.trim() || !patch.changes.length) return "配置修改必须包含原因、幂等键和至少一项变更。"; for (const change of patch.changes) { const field = configurationCatalog.find((candidate) => candidate.key === change.key); if (!field) return `字段 ${change.key} 不在插件目录中。`; if (!change.value.trim()) return `字段 ${field.label} 不能为空。`; if ((field.control === "number" || field.control === "port") && (!Number.isInteger(Number(change.value)) || (field.minimum !== undefined && Number(change.value) < field.minimum) || (field.maximum !== undefined && Number(change.value) > field.maximum))) return `字段 ${field.label} 超出允许范围。`; } return null; }
|
|
export function validateStatePatch(fields: Array<{ fieldKey: string; before: number; after: number }>): string | null { if (!fields.length) return "状态修改至少需要一个字段。"; for (const field of fields) { if (!supportsStateField(field.fieldKey)) return `字段 ${field.fieldKey} 格式无效。`; if (!Number.isFinite(field.before) || !Number.isFinite(field.after)) return `字段 ${field.fieldKey} 必须是数字。`; } return null; }
|
|
export function validateVehicleSpawn(spawn: SCUMVehicleSpawn): string | null { if (!/^[A-Za-z][A-Za-z0-9_]{2,63}$/.test(spawn.vehicleCode)) return "载具代码格式无效。"; if (!vehicleSpawnCatalog.some((candidate) => candidate.code === spawn.vehicleCode)) return "载具代码未在插件目录中声明。"; return null; }
|