diablo2-web/plugins/lighting-presets/index.ts

171 lines
5.2 KiB
TypeScript

/**
* Lighting Presets Plugin (`plugins/lighting-presets/index.ts` — Issue #715).
*
* Isolates the non-1.13c manual lighting preset selector (`noon`, `dusk`, `night`,
* `torch`, `cold`, `fullbright`) outside core `src/`. When disabled, `PluginHost`
* releases the capability claim and strictly enforces 1.13c native level lighting (`auto`).
*/
import {
CLIENT_LIGHTING_PRESET_ORDER,
LIGHTING_PRESETS,
VALID_LIGHTING_PRESETS,
type ClientLightingPreset,
type D2WebPlugin,
type PluginContext,
type PluginInstance,
type PluginStatus,
type PluginToolbarSelectOption,
} from '../../src/client/plugin-host/api.ts'
const LIGHTING_SELECT_OPTIONS: readonly PluginToolbarSelectOption[] =
CLIENT_LIGHTING_PRESET_ORDER.map((presetId) => {
const cfg = LIGHTING_PRESETS[presetId]
return {
value: presetId,
label: {
zh: cfg.labelZh,
en: cfg.labelEn,
},
}
})
function isLightingPreset(value: unknown): value is ClientLightingPreset {
return (
typeof value === 'string' &&
(VALID_LIGHTING_PRESETS as readonly string[]).includes(value)
)
}
export interface LightingPresetsPluginInstance extends PluginInstance {
getPreset(): ClientLightingPreset
setPreset(preset: ClientLightingPreset): void
}
export function createLightingPresetsPlugin(): D2WebPlugin {
return {
id: 'lighting-presets',
name: {
zh: '光照预设切换',
en: 'Lighting Presets',
},
description: {
zh: '非 1.13c 增强:允许手动切换全局环境光与火把照明预设(正午/黄昏/黑夜/火把/寒光/全亮)。关闭插件后严格恢复 1.13c 原版关卡环境光(自动)。',
en: 'Non-1.13c enhancement: manually override ambient RGB and player torch radius (Noon, Dusk, Night, Torch, Cold, Fullbright). When disabled, strictly enforces 1.13c level lighting (Auto).',
},
defaultEnabled: true,
settings: [
{
kind: 'select',
key: 'preset',
label: {
zh: '光照模式',
en: 'Lighting Mode',
},
default: 'auto',
options: LIGHTING_SELECT_OPTIONS,
},
{
kind: 'boolean',
key: 'showToolbarShortcut',
label: {
zh: '在工具栏显示快捷下拉框',
en: 'Show selector in toolbar',
},
default: true,
},
],
activate(ctx: PluginContext): LightingPresetsPluginInstance {
const storedSetting = ctx.settings.get('preset')
const initialPreset: ClientLightingPreset = isLightingPreset(storedSetting)
? storedSetting
: 'auto'
ctx.client.setLightingPreset(initialPreset)
const unsubClient = ctx.client.subscribeLightingPreset((clientPreset) => {
if (ctx.settings.get('preset') !== clientPreset) {
ctx.settings.set('preset', clientPreset)
}
ctx.notifyStatusChanged()
})
let removeToolbarSelect: (() => void) | null = null
const syncToolbarShortcut = (): void => {
const show = ctx.settings.get('showToolbarShortcut') === true
if (show && !removeToolbarSelect) {
removeToolbarSelect = ctx.toolbar.addSelect({
id: 'preset',
selectDomId: 'd2-toolbar-lighting-select',
label: {
zh: '光照',
en: 'Lighting',
},
options: LIGHTING_SELECT_OPTIONS,
getValue: () => {
const raw = ctx.settings.get('preset')
return isLightingPreset(raw) ? raw : 'auto'
},
onChange: (value: string) => {
if (!isLightingPreset(value)) {
throw new Error(`Invalid lighting preset: ${value}`)
}
ctx.settings.set('preset', value)
},
})
} else if (!show && removeToolbarSelect) {
removeToolbarSelect()
removeToolbarSelect = null
}
}
syncToolbarShortcut()
const unsubSettings = ctx.settings.subscribe((key) => {
if (key === 'preset') {
const next = ctx.settings.get('preset')
if (isLightingPreset(next)) {
ctx.client.setLightingPreset(next)
ctx.notifyStatusChanged()
}
} else if (key === 'showToolbarShortcut') {
syncToolbarShortcut()
}
})
const getStatus = (): PluginStatus => {
const preset = ctx.client.getLightingPreset()
const cfg = LIGHTING_PRESETS[preset]
return {
level: 'ok',
text: {
zh: `当前:${cfg.labelZh}`,
en: `Preset: ${cfg.labelEn}`,
},
}
}
return {
getPreset: () => ctx.client.getLightingPreset(),
setPreset: (preset: ClientLightingPreset) => {
if (!isLightingPreset(preset)) {
throw new Error(`Invalid lighting preset: ${String(preset)}`)
}
ctx.settings.set('preset', preset)
},
getStatus,
deactivate(): void {
unsubClient()
unsubSettings()
if (removeToolbarSelect) {
removeToolbarSelect()
removeToolbarSelect = null
}
},
}
},
}
}
export const lightingPresetsPlugin: D2WebPlugin = createLightingPresetsPlugin()