forked from xiangwang25/whale-town-front-v2
152 lines
5.2 KiB
GDScript
152 lines
5.2 KiB
GDScript
extends Node
|
|
|
|
# ============================================================================
|
|
# NotificationSoundManager.gd - 提醒音效管理器
|
|
# ============================================================================
|
|
# 监听聊天和好友事件,播放项目内正式 UI 提醒音效资源。
|
|
# ============================================================================
|
|
|
|
const MIN_PLAY_INTERVAL_SEC: float = 0.18
|
|
const WORLD_NOTIFICATION_PATH: String = "res://assets/audio/ui/notify_world.wav"
|
|
const PRIVATE_NOTIFICATION_PATH: String = "res://assets/audio/ui/notify_private.wav"
|
|
const FRIEND_NOTIFICATION_PATH: String = "res://assets/audio/ui/notify_friend.wav"
|
|
|
|
var _player: AudioStreamPlayer
|
|
var _worldStream: AudioStreamWAV
|
|
var _privateStream: AudioStreamWAV
|
|
var _friendStream: AudioStreamWAV
|
|
var _lastPlayedAt: float = 0.0
|
|
var _seenFriendRequestKeys: Dictionary = {}
|
|
|
|
func _ready() -> void:
|
|
_build_player()
|
|
_load_streams()
|
|
_subscribe_to_events()
|
|
|
|
func _exit_tree() -> void:
|
|
var eventSystem := _get_event_system()
|
|
if eventSystem != null:
|
|
eventSystem.call("disconnect_event", EventNames.CHAT_MESSAGE_RECEIVED, _on_chat_message_received, self)
|
|
eventSystem.call("disconnect_event", EventNames.CHAT_FRIENDS_UPDATED, _on_friends_updated, self)
|
|
eventSystem.call("disconnect_event", EventNames.CHAT_ERROR_OCCURRED, _on_chat_error, self)
|
|
|
|
func play_notification(kind: String = "world") -> void:
|
|
if _settings_bool("mute_ui_sfx", false):
|
|
return
|
|
|
|
var now := Time.get_unix_time_from_system()
|
|
if now - _lastPlayedAt < MIN_PLAY_INTERVAL_SEC:
|
|
return
|
|
_lastPlayedAt = now
|
|
|
|
if not is_instance_valid(_player):
|
|
return
|
|
var stream := _stream_for_kind(kind)
|
|
if stream == null:
|
|
return
|
|
_player.stream = stream
|
|
_player.play()
|
|
|
|
func should_play_message_notification(data: Dictionary) -> bool:
|
|
if bool(data.get("is_self", false)):
|
|
return false
|
|
|
|
var scope := str(data.get("scope", "")).strip_edges().to_lower()
|
|
var isPrivate := bool(data.get("is_private", false)) or scope == "private"
|
|
if isPrivate:
|
|
return _settings_bool("private_notifications", true)
|
|
return _settings_bool("world_notifications", true)
|
|
|
|
func get_notification_asset_path(kind: String = "world") -> String:
|
|
match kind:
|
|
"private":
|
|
return PRIVATE_NOTIFICATION_PATH
|
|
"friend":
|
|
return FRIEND_NOTIFICATION_PATH
|
|
_:
|
|
return WORLD_NOTIFICATION_PATH
|
|
|
|
func _build_player() -> void:
|
|
_player = AudioStreamPlayer.new()
|
|
_player.name = "NotificationAudioPlayer"
|
|
_player.bus = "SFX"
|
|
add_child(_player)
|
|
|
|
func _load_streams() -> void:
|
|
_worldStream = _load_wav_stream(WORLD_NOTIFICATION_PATH)
|
|
_privateStream = _load_wav_stream(PRIVATE_NOTIFICATION_PATH)
|
|
_friendStream = _load_wav_stream(FRIEND_NOTIFICATION_PATH)
|
|
|
|
func _load_wav_stream(path: String) -> AudioStreamWAV:
|
|
var resource := load(path)
|
|
if not (resource is AudioStreamWAV):
|
|
push_warning("NotificationSoundManager: 提醒音效加载失败: %s" % path)
|
|
return null
|
|
return resource as AudioStreamWAV
|
|
|
|
func _stream_for_kind(kind: String) -> AudioStream:
|
|
match kind:
|
|
"private":
|
|
return _privateStream
|
|
"friend":
|
|
return _friendStream
|
|
_:
|
|
return _worldStream
|
|
|
|
func _subscribe_to_events() -> void:
|
|
var eventSystem := _get_event_system()
|
|
if eventSystem == null:
|
|
push_warning("NotificationSoundManager: EventSystem autoload is not available.")
|
|
return
|
|
eventSystem.call("connect_event", EventNames.CHAT_MESSAGE_RECEIVED, _on_chat_message_received, self)
|
|
eventSystem.call("connect_event", EventNames.CHAT_FRIENDS_UPDATED, _on_friends_updated, self)
|
|
eventSystem.call("connect_event", EventNames.CHAT_ERROR_OCCURRED, _on_chat_error, self)
|
|
|
|
func _on_chat_message_received(data: Dictionary) -> void:
|
|
if not should_play_message_notification(data):
|
|
return
|
|
var scope := str(data.get("scope", "")).strip_edges().to_lower()
|
|
var isPrivate := bool(data.get("is_private", false)) or scope == "private"
|
|
play_notification("private" if isPrivate else "world")
|
|
|
|
func _on_friends_updated(data: Dictionary) -> void:
|
|
if not _settings_bool("friend_request_notifications", true):
|
|
return
|
|
|
|
var requestsVariant: Variant = data.get("requests", [])
|
|
if not (requestsVariant is Array):
|
|
return
|
|
|
|
var shouldPlay := false
|
|
for requestVariant in requestsVariant:
|
|
if not (requestVariant is Dictionary):
|
|
continue
|
|
var key := _friend_request_key(requestVariant as Dictionary)
|
|
if key.is_empty() or _seenFriendRequestKeys.has(key):
|
|
continue
|
|
_seenFriendRequestKeys[key] = true
|
|
shouldPlay = true
|
|
|
|
if shouldPlay:
|
|
play_notification("friend")
|
|
|
|
func _on_chat_error(data: Dictionary) -> void:
|
|
var errorCode := str(data.get("error_code", ""))
|
|
if errorCode == "FRIEND_REQUEST_SENT" and _settings_bool("friend_request_notifications", true):
|
|
play_notification("friend")
|
|
|
|
func _friend_request_key(request: Dictionary) -> String:
|
|
var userId := str(request.get("user_id", request.get("userId", ""))).strip_edges()
|
|
if not userId.is_empty():
|
|
return userId
|
|
return str(request.get("username", "")).strip_edges()
|
|
|
|
func _settings_bool(key: String, defaultValue: bool) -> bool:
|
|
var settingsManager := get_node_or_null("/root/SettingsManager")
|
|
if settingsManager != null and settingsManager.has_method("get_bool"):
|
|
return bool(settingsManager.call("get_bool", key))
|
|
return defaultValue
|
|
|
|
func _get_event_system() -> Node:
|
|
return get_node_or_null("/root/EventSystem")
|