Split media vs emit volume for radio and widget
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
// Maintainer-controlled web client version.
|
// Maintainer-controlled web client version.
|
||||||
// Format: YYYY.MM.DD Rn (example: 2026.02.20 R2)
|
// Format: YYYY.MM.DD Rn (example: 2026.02.20 R2)
|
||||||
window.CHGRID_WEB_VERSION = "2026.02.21 R126";
|
window.CHGRID_WEB_VERSION = "2026.02.21 R127";
|
||||||
// Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid.
|
// Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid.
|
||||||
window.CHGRID_TIME_ZONE = "America/Detroit";
|
window.CHGRID_TIME_ZONE = "America/Detroit";
|
||||||
|
|||||||
@@ -135,7 +135,9 @@ export class ItemEmitRuntime {
|
|||||||
});
|
});
|
||||||
const gainValue = mix?.gain ?? 0;
|
const gainValue = mix?.gain ?? 0;
|
||||||
const panValue = mix?.pan ?? 0;
|
const panValue = mix?.pan ?? 0;
|
||||||
output.gain.gain.linearRampToValueAtTime(gainValue, audioCtx.currentTime + 0.1);
|
const emitVolumeRaw = Number(item.params.emitVolume ?? 100);
|
||||||
|
const emitVolume = Number.isFinite(emitVolumeRaw) ? Math.max(0, Math.min(100, emitVolumeRaw)) / 100 : 1;
|
||||||
|
output.gain.gain.linearRampToValueAtTime(gainValue * emitVolume, audioCtx.currentTime + 0.1);
|
||||||
if (output.panner) {
|
if (output.panner) {
|
||||||
const resolvedPan = this.audio.getOutputMode() === 'mono' ? 0 : Math.max(-1, Math.min(1, panValue));
|
const resolvedPan = this.audio.getOutputMode() === 'mono' ? 0 : Math.max(-1, Math.min(1, panValue));
|
||||||
output.panner.pan.linearRampToValueAtTime(resolvedPan, audioCtx.currentTime + 0.1);
|
output.panner.pan.linearRampToValueAtTime(resolvedPan, audioCtx.currentTime + 0.1);
|
||||||
|
|||||||
@@ -203,8 +203,8 @@ export class RadioStationRuntime {
|
|||||||
}
|
}
|
||||||
const streamUrl = String(item.params.streamUrl ?? '').trim();
|
const streamUrl = String(item.params.streamUrl ?? '').trim();
|
||||||
const enabled = item.params.enabled !== false;
|
const enabled = item.params.enabled !== false;
|
||||||
const volume = Number(item.params.volume ?? 50);
|
const mediaVolume = Number(item.params.mediaVolume ?? 50);
|
||||||
const normalizedVolume = Number.isFinite(volume) ? Math.max(0, Math.min(100, volume)) / 100 : 0.5;
|
const normalizedVolume = Number.isFinite(mediaVolume) ? Math.max(0, Math.min(100, mediaVolume)) / 100 : 0.5;
|
||||||
const effect = normalizeRadioEffect(item.params.effect);
|
const effect = normalizeRadioEffect(item.params.effect);
|
||||||
const effectValue = normalizeRadioEffectValue(item.params.effectValue);
|
const effectValue = normalizeRadioEffectValue(item.params.effectValue);
|
||||||
this.applyEffect(output, audioCtx, effect, effectValue);
|
this.applyEffect(output, audioCtx, effect, effectValue);
|
||||||
|
|||||||
@@ -48,11 +48,11 @@ const DEFAULT_CLOCK_TIME_ZONE_OPTIONS = [
|
|||||||
const DEFAULT_ITEM_TYPE_SEQUENCE: ItemType[] = ['clock', 'dice', 'radio_station', 'wheel', 'widget'];
|
const DEFAULT_ITEM_TYPE_SEQUENCE: ItemType[] = ['clock', 'dice', 'radio_station', 'wheel', 'widget'];
|
||||||
|
|
||||||
const DEFAULT_ITEM_TYPE_EDITABLE_PROPERTIES: Record<ItemType, string[]> = {
|
const DEFAULT_ITEM_TYPE_EDITABLE_PROPERTIES: Record<ItemType, string[]> = {
|
||||||
radio_station: ['title', 'streamUrl', 'enabled', 'channel', 'volume', 'effect', 'effectValue', 'facing', 'emitRange'],
|
radio_station: ['title', 'streamUrl', 'enabled', 'channel', 'mediaVolume', 'effect', 'effectValue', 'facing', 'emitRange'],
|
||||||
dice: ['title', 'sides', 'number'],
|
dice: ['title', 'sides', 'number'],
|
||||||
wheel: ['title', 'spaces'],
|
wheel: ['title', 'spaces'],
|
||||||
clock: ['title', 'timeZone', 'use24Hour'],
|
clock: ['title', 'timeZone', 'use24Hour'],
|
||||||
widget: ['title', 'enabled', 'directional', 'facing', 'emitRange', 'useSound', 'emitSound'],
|
widget: ['title', 'enabled', 'directional', 'facing', 'emitRange', 'emitVolume', 'useSound', 'emitSound'],
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_ITEM_TYPE_GLOBAL_PROPERTIES: Record<ItemType, Record<string, string | number | boolean>> = {
|
const DEFAULT_ITEM_TYPE_GLOBAL_PROPERTIES: Record<ItemType, Record<string, string | number | boolean>> = {
|
||||||
@@ -193,6 +193,8 @@ export function itemTypeLabel(type: ItemType): string {
|
|||||||
export function itemPropertyLabel(key: string): string {
|
export function itemPropertyLabel(key: string): string {
|
||||||
if (key === 'use24Hour') return 'use 24 hour format';
|
if (key === 'use24Hour') return 'use 24 hour format';
|
||||||
if (key === 'emitRange') return 'emit range';
|
if (key === 'emitRange') return 'emit range';
|
||||||
|
if (key === 'mediaVolume') return 'media volume';
|
||||||
|
if (key === 'emitVolume') return 'emit volume';
|
||||||
if (key === 'useSound') return 'use sound';
|
if (key === 'useSound') return 'use sound';
|
||||||
if (key === 'emitSound') return 'emit sound';
|
if (key === 'emitSound') return 'emit sound';
|
||||||
return key;
|
return key;
|
||||||
|
|||||||
@@ -749,7 +749,8 @@ function inferItemPropertyValueType(item: WorldItem, key: string): string | unde
|
|||||||
key === 'x' ||
|
key === 'x' ||
|
||||||
key === 'y' ||
|
key === 'y' ||
|
||||||
key === 'version' ||
|
key === 'version' ||
|
||||||
key === 'volume' ||
|
key === 'mediaVolume' ||
|
||||||
|
key === 'emitVolume' ||
|
||||||
key === 'effectValue' ||
|
key === 'effectValue' ||
|
||||||
key === 'facing' ||
|
key === 'facing' ||
|
||||||
key === 'emitRange' ||
|
key === 'emitRange' ||
|
||||||
@@ -2138,14 +2139,22 @@ function handleItemPropertyEditModeInput(code: string, key: string, ctrlKey: boo
|
|||||||
}
|
}
|
||||||
const directional = ['on', 'true', '1', 'yes'].includes(normalized);
|
const directional = ['on', 'true', '1', 'yes'].includes(normalized);
|
||||||
signaling.send({ type: 'item_update', itemId, params: { directional } });
|
signaling.send({ type: 'item_update', itemId, params: { directional } });
|
||||||
} else if (propertyKey === 'volume') {
|
} else if (propertyKey === 'mediaVolume') {
|
||||||
const parsed = validateNumericItemPropertyInput(item, propertyKey, value, true);
|
const parsed = validateNumericItemPropertyInput(item, propertyKey, value, true);
|
||||||
if (!parsed.ok) {
|
if (!parsed.ok) {
|
||||||
updateStatus(parsed.message);
|
updateStatus(parsed.message);
|
||||||
audio.sfxUiCancel();
|
audio.sfxUiCancel();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
signaling.send({ type: 'item_update', itemId, params: { volume: parsed.value } });
|
signaling.send({ type: 'item_update', itemId, params: { mediaVolume: parsed.value } });
|
||||||
|
} else if (propertyKey === 'emitVolume') {
|
||||||
|
const parsed = validateNumericItemPropertyInput(item, propertyKey, value, true);
|
||||||
|
if (!parsed.ok) {
|
||||||
|
updateStatus(parsed.message);
|
||||||
|
audio.sfxUiCancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
signaling.send({ type: 'item_update', itemId, params: { emitVolume: parsed.value } });
|
||||||
} else if (propertyKey === 'effect') {
|
} else if (propertyKey === 'effect') {
|
||||||
const normalized = value.trim().toLowerCase() as EffectId;
|
const normalized = value.trim().toLowerCase() as EffectId;
|
||||||
if (!EFFECT_IDS.has(normalized)) {
|
if (!EFFECT_IDS.has(normalized)) {
|
||||||
|
|||||||
@@ -62,7 +62,7 @@
|
|||||||
"streamUrl": "",
|
"streamUrl": "",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"channel": "stereo",
|
"channel": "stereo",
|
||||||
"volume": 50,
|
"mediaVolume": 50,
|
||||||
"effect": "off",
|
"effect": "off",
|
||||||
"effectValue": 50,
|
"effectValue": 50,
|
||||||
"facing": 0,
|
"facing": 0,
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
- `streamUrl`: string, empty allowed until configured.
|
- `streamUrl`: string, empty allowed until configured.
|
||||||
- `enabled`: boolean on/off flag.
|
- `enabled`: boolean on/off flag.
|
||||||
- UI behavior: in property menu, `Enter` toggles on/off directly.
|
- UI behavior: in property menu, `Enter` toggles on/off directly.
|
||||||
- `volume`: integer, range `0-100`, default `50`.
|
- `mediaVolume`: integer, range `0-100`, default `50`.
|
||||||
- `channel`: one of `stereo | mono | left | right`, default `stereo`.
|
- `channel`: one of `stereo | mono | left | right`, default `stereo`.
|
||||||
- `effect`: one of `reverb | echo | flanger | high_pass | low_pass | off`, default `off`.
|
- `effect`: one of `reverb | echo | flanger | high_pass | low_pass | off`, default `off`.
|
||||||
- `effectValue`: number, range `0-100`, precision `0.1`.
|
- `effectValue`: number, range `0-100`, precision `0.1`.
|
||||||
@@ -136,6 +136,7 @@
|
|||||||
"directional": false,
|
"directional": false,
|
||||||
"facing": 0,
|
"facing": 0,
|
||||||
"emitRange": 15,
|
"emitRange": 15,
|
||||||
|
"emitVolume": 100,
|
||||||
"useSound": "",
|
"useSound": "",
|
||||||
"emitSound": ""
|
"emitSound": ""
|
||||||
}
|
}
|
||||||
@@ -145,6 +146,7 @@
|
|||||||
- `directional`: boolean (or `on/off` in updates), default `false`.
|
- `directional`: boolean (or `on/off` in updates), default `false`.
|
||||||
- `facing`: number, range `0-360`, precision `0.1`.
|
- `facing`: number, range `0-360`, precision `0.1`.
|
||||||
- `emitRange`: integer, range `1-20`, default `15`.
|
- `emitRange`: integer, range `1-20`, default `15`.
|
||||||
|
- `emitVolume`: integer, range `0-100`, default `100`.
|
||||||
- `useSound`: empty, filename (assumed under `sounds/`), or full URL.
|
- `useSound`: empty, filename (assumed under `sounds/`), or full URL.
|
||||||
- `emitSound`: empty, filename (assumed under `sounds/`), or full URL.
|
- `emitSound`: empty, filename (assumed under `sounds/`), or full URL.
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ This is behavior-focused documentation for item types and their defaults.
|
|||||||
- `streamUrl=""`
|
- `streamUrl=""`
|
||||||
- `enabled=true`
|
- `enabled=true`
|
||||||
- `channel="stereo"`
|
- `channel="stereo"`
|
||||||
- `volume=50`
|
- `mediaVolume=50`
|
||||||
- `effect="off"`
|
- `effect="off"`
|
||||||
- `effectValue=50`
|
- `effectValue=50`
|
||||||
- `facing=0`
|
- `facing=0`
|
||||||
@@ -39,7 +39,7 @@ This is behavior-focused documentation for item types and their defaults.
|
|||||||
|
|
||||||
### Validation
|
### Validation
|
||||||
- `channel`: `stereo | mono | left | right`
|
- `channel`: `stereo | mono | left | right`
|
||||||
- `volume`: integer `0..100`
|
- `mediaVolume`: integer `0..100`
|
||||||
- `effect`: `reverb | echo | flanger | high_pass | low_pass | off`
|
- `effect`: `reverb | echo | flanger | high_pass | low_pass | off`
|
||||||
- `effectValue`: number `0..100` with `0.1` precision
|
- `effectValue`: number `0..100` with `0.1` precision
|
||||||
- `facing`: number `0..360` with `0.1` precision
|
- `facing`: number `0..360` with `0.1` precision
|
||||||
@@ -119,6 +119,7 @@ This is behavior-focused documentation for item types and their defaults.
|
|||||||
- `directional=false`
|
- `directional=false`
|
||||||
- `facing=0`
|
- `facing=0`
|
||||||
- `emitRange=15`
|
- `emitRange=15`
|
||||||
|
- `emitVolume=100`
|
||||||
- `useSound=""`
|
- `useSound=""`
|
||||||
- `emitSound=""`
|
- `emitSound=""`
|
||||||
- Global:
|
- Global:
|
||||||
@@ -136,6 +137,7 @@ This is behavior-focused documentation for item types and their defaults.
|
|||||||
- `directional`: boolean or on/off style input
|
- `directional`: boolean or on/off style input
|
||||||
- `facing`: number `0..360` with `0.1` precision
|
- `facing`: number `0..360` with `0.1` precision
|
||||||
- `emitRange`: integer `1..20`
|
- `emitRange`: integer `1..20`
|
||||||
|
- `emitVolume`: integer `0..100`
|
||||||
- `useSound`: empty, filename (assumed under `sounds/`), or full URL
|
- `useSound`: empty, filename (assumed under `sounds/`), or full URL
|
||||||
- `emitSound`: empty, filename (assumed under `sounds/`), or full URL
|
- `emitSound`: empty, filename (assumed under `sounds/`), or full URL
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ EDITABLE_PROPERTIES: tuple[str, ...] = (
|
|||||||
"streamUrl",
|
"streamUrl",
|
||||||
"enabled",
|
"enabled",
|
||||||
"channel",
|
"channel",
|
||||||
"volume",
|
"mediaVolume",
|
||||||
"effect",
|
"effect",
|
||||||
"effectValue",
|
"effectValue",
|
||||||
"facing",
|
"facing",
|
||||||
@@ -32,7 +32,7 @@ DEFAULT_PARAMS: dict = {
|
|||||||
"streamUrl": "",
|
"streamUrl": "",
|
||||||
"enabled": True,
|
"enabled": True,
|
||||||
"channel": "stereo",
|
"channel": "stereo",
|
||||||
"volume": 50,
|
"mediaVolume": 50,
|
||||||
"effect": "off",
|
"effect": "off",
|
||||||
"effectValue": 50,
|
"effectValue": 50,
|
||||||
"facing": 0,
|
"facing": 0,
|
||||||
@@ -47,9 +47,9 @@ PROPERTY_METADATA: dict[str, dict[str, object]] = {
|
|||||||
"streamUrl": {"valueType": "text", "tooltip": "Audio stream URL used by this radio."},
|
"streamUrl": {"valueType": "text", "tooltip": "Audio stream URL used by this radio."},
|
||||||
"enabled": {"valueType": "boolean", "tooltip": "Turns playback on or off for this radio."},
|
"enabled": {"valueType": "boolean", "tooltip": "Turns playback on or off for this radio."},
|
||||||
"channel": {"valueType": "list", "tooltip": "Select how the station audio channels are rendered."},
|
"channel": {"valueType": "list", "tooltip": "Select how the station audio channels are rendered."},
|
||||||
"volume": {
|
"mediaVolume": {
|
||||||
"valueType": "number",
|
"valueType": "number",
|
||||||
"tooltip": "Playback volume percent for this radio.",
|
"tooltip": "Playback media volume percent for this radio.",
|
||||||
"range": {"min": 0, "max": 100, "step": 1},
|
"range": {"min": 0, "max": 100, "step": 1},
|
||||||
},
|
},
|
||||||
"effect": {"valueType": "list", "tooltip": "Select the active radio effect."},
|
"effect": {"valueType": "list", "tooltip": "Select the active radio effect."},
|
||||||
@@ -100,12 +100,12 @@ def validate_update(item: WorldItem, next_params: dict) -> dict:
|
|||||||
next_params["enabled"] = enabled
|
next_params["enabled"] = enabled
|
||||||
|
|
||||||
try:
|
try:
|
||||||
volume = int(next_params.get("volume", 50))
|
media_volume = int(next_params.get("mediaVolume", 50))
|
||||||
except (TypeError, ValueError) as exc:
|
except (TypeError, ValueError) as exc:
|
||||||
raise ValueError("volume must be a number.") from exc
|
raise ValueError("mediaVolume must be a number.") from exc
|
||||||
if not (0 <= volume <= 100):
|
if not (0 <= media_volume <= 100):
|
||||||
raise ValueError("volume must be between 0 and 100.")
|
raise ValueError("mediaVolume must be between 0 and 100.")
|
||||||
next_params["volume"] = volume
|
next_params["mediaVolume"] = media_volume
|
||||||
|
|
||||||
effect = str(next_params.get("effect", "off")).strip().lower()
|
effect = str(next_params.get("effect", "off")).strip().lower()
|
||||||
if effect not in EFFECT_OPTIONS:
|
if effect not in EFFECT_OPTIONS:
|
||||||
@@ -153,4 +153,3 @@ def use_item(item: WorldItem, nickname: str, _clock_formatter: Callable[[dict],
|
|||||||
others_message=f"{nickname} turns {state_text} {item.title}.",
|
others_message=f"{nickname} turns {state_text} {item.title}.",
|
||||||
updated_params={**item.params, "enabled": next_enabled},
|
updated_params={**item.params, "enabled": next_enabled},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,16 @@ from .helpers import parse_bool_like, toggle_bool_param
|
|||||||
|
|
||||||
LABEL = "widget"
|
LABEL = "widget"
|
||||||
TOOLTIP = "A basic item. Make it a beacon or whatever you want."
|
TOOLTIP = "A basic item. Make it a beacon or whatever you want."
|
||||||
EDITABLE_PROPERTIES: tuple[str, ...] = ("title", "enabled", "directional", "facing", "emitRange", "useSound", "emitSound")
|
EDITABLE_PROPERTIES: tuple[str, ...] = (
|
||||||
|
"title",
|
||||||
|
"enabled",
|
||||||
|
"directional",
|
||||||
|
"facing",
|
||||||
|
"emitRange",
|
||||||
|
"emitVolume",
|
||||||
|
"useSound",
|
||||||
|
"emitSound",
|
||||||
|
)
|
||||||
CAPABILITIES: tuple[str, ...] = ("editable", "carryable", "deletable", "usable")
|
CAPABILITIES: tuple[str, ...] = ("editable", "carryable", "deletable", "usable")
|
||||||
USE_SOUND: str | None = None
|
USE_SOUND: str | None = None
|
||||||
EMIT_SOUND: str | None = None
|
EMIT_SOUND: str | None = None
|
||||||
@@ -23,6 +32,7 @@ DEFAULT_PARAMS: dict = {
|
|||||||
"directional": False,
|
"directional": False,
|
||||||
"facing": 0,
|
"facing": 0,
|
||||||
"emitRange": 15,
|
"emitRange": 15,
|
||||||
|
"emitVolume": 100,
|
||||||
"useSound": "",
|
"useSound": "",
|
||||||
"emitSound": "",
|
"emitSound": "",
|
||||||
}
|
}
|
||||||
@@ -41,6 +51,11 @@ PROPERTY_METADATA: dict[str, dict[str, object]] = {
|
|||||||
"tooltip": "Maximum distance in squares for emitted sound.",
|
"tooltip": "Maximum distance in squares for emitted sound.",
|
||||||
"range": {"min": 1, "max": 20, "step": 1},
|
"range": {"min": 1, "max": 20, "step": 1},
|
||||||
},
|
},
|
||||||
|
"emitVolume": {
|
||||||
|
"valueType": "number",
|
||||||
|
"tooltip": "Emitted sound volume percent.",
|
||||||
|
"range": {"min": 0, "max": 100, "step": 1},
|
||||||
|
},
|
||||||
"useSound": {"valueType": "sound", "tooltip": "Sound played on use. Filename assumes sounds folder, or use full URL."},
|
"useSound": {"valueType": "sound", "tooltip": "Sound played on use. Filename assumes sounds folder, or use full URL."},
|
||||||
"emitSound": {"valueType": "sound", "tooltip": "Looping emitted sound. Filename assumes sounds folder, or use full URL."},
|
"emitSound": {"valueType": "sound", "tooltip": "Looping emitted sound. Filename assumes sounds folder, or use full URL."},
|
||||||
}
|
}
|
||||||
@@ -90,6 +105,14 @@ def validate_update(item: WorldItem, next_params: dict) -> dict:
|
|||||||
raise ValueError("emitRange must be between 1 and 20.")
|
raise ValueError("emitRange must be between 1 and 20.")
|
||||||
next_params["emitRange"] = emit_range
|
next_params["emitRange"] = emit_range
|
||||||
|
|
||||||
|
try:
|
||||||
|
emit_volume = int(next_params.get("emitVolume", item.params.get("emitVolume", 100)))
|
||||||
|
except (TypeError, ValueError) as exc:
|
||||||
|
raise ValueError("emitVolume must be an integer between 0 and 100.") from exc
|
||||||
|
if not (0 <= emit_volume <= 100):
|
||||||
|
raise ValueError("emitVolume must be between 0 and 100.")
|
||||||
|
next_params["emitVolume"] = emit_volume
|
||||||
|
|
||||||
next_params["useSound"] = _normalize_sound_value(next_params.get("useSound", item.params.get("useSound", "")))
|
next_params["useSound"] = _normalize_sound_value(next_params.get("useSound", item.params.get("useSound", "")))
|
||||||
next_params["emitSound"] = _normalize_sound_value(next_params.get("emitSound", item.params.get("emitSound", "")))
|
next_params["emitSound"] = _normalize_sound_value(next_params.get("emitSound", item.params.get("emitSound", "")))
|
||||||
return next_params
|
return next_params
|
||||||
|
|||||||
@@ -132,6 +132,13 @@ async def test_radio_channel_update_validates(monkeypatch: pytest.MonkeyPatch) -
|
|||||||
assert send_payloads[-1].ok is False
|
assert send_payloads[-1].ok is False
|
||||||
assert "facing must be between 0 and 360" in send_payloads[-1].message.lower()
|
assert "facing must be between 0 and 360" in send_payloads[-1].message.lower()
|
||||||
|
|
||||||
|
await server._handle_message(
|
||||||
|
client,
|
||||||
|
json.dumps({"type": "item_update", "itemId": item.id, "params": {"mediaVolume": 12}}),
|
||||||
|
)
|
||||||
|
assert send_payloads[-1].ok is True
|
||||||
|
assert item.params.get("mediaVolume") == 12
|
||||||
|
|
||||||
await server._handle_message(
|
await server._handle_message(
|
||||||
client,
|
client,
|
||||||
json.dumps({"type": "item_update", "itemId": item.id, "params": {"emitRange": 12}}),
|
json.dumps({"type": "item_update", "itemId": item.id, "params": {"emitRange": 12}}),
|
||||||
@@ -277,6 +284,7 @@ async def test_widget_update_and_use(monkeypatch: pytest.MonkeyPatch) -> None:
|
|||||||
"directional": True,
|
"directional": True,
|
||||||
"facing": 123.4,
|
"facing": 123.4,
|
||||||
"emitRange": 7,
|
"emitRange": 7,
|
||||||
|
"emitVolume": 42,
|
||||||
"useSound": "ping.ogg",
|
"useSound": "ping.ogg",
|
||||||
"emitSound": "https://example.com/ambient.ogg",
|
"emitSound": "https://example.com/ambient.ogg",
|
||||||
},
|
},
|
||||||
@@ -287,6 +295,7 @@ async def test_widget_update_and_use(monkeypatch: pytest.MonkeyPatch) -> None:
|
|||||||
assert item.params.get("directional") is True
|
assert item.params.get("directional") is True
|
||||||
assert item.params.get("facing") == 123.4
|
assert item.params.get("facing") == 123.4
|
||||||
assert item.params.get("emitRange") == 7
|
assert item.params.get("emitRange") == 7
|
||||||
|
assert item.params.get("emitVolume") == 42
|
||||||
assert item.params.get("useSound") == "sounds/ping.ogg"
|
assert item.params.get("useSound") == "sounds/ping.ogg"
|
||||||
assert item.params.get("emitSound") == "https://example.com/ambient.ogg"
|
assert item.params.get("emitSound") == "https://example.com/ambient.ogg"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user