@tool extends Control class_name ChatBox enum ChatDock { BOTTOM, LEFT, TOP, RIGHT } @onready var chat_history: ScrollContainer = %ChatHistory @onready var history: VBoxContainer = %History @onready var height: int = 250 @onready var width: int = 200 @export var dock: ChatDock = ChatDock.BOTTOM: set(value): dock = value if not is_node_ready(): return _orientate_chatbox() func _ready() -> void: var waiting_for_ready := false if Engine.is_editor_hint(): return while Globals.twitcher == null or !Globals.twitcher.is_node_ready(): if not waiting_for_ready: print("Waiting for Twitcher Ready...") waiting_for_ready = true await get_tree().process_frame _orientate_chatbox() Globals.twitcher.chat.message_received.connect(_handle_chat) func _orientate_chatbox() -> void: match dock: ChatDock.BOTTOM: chat_history.custom_minimum_size = Vector2(1550,265) chat_history.size = Vector2(1550,265) chat_history.position = Vector2(0, get_viewport_rect().size.y - 265) #chat_history.set_anchors_preset(Control.PRESET_BOTTOM_WIDE) #chat_history.custom_minimum_size = Vector2(0,height) ChatDock.LEFT: chat_history.custom_minimum_size = Vector2(500,get_viewport_rect().size.y) chat_history.size = Vector2(500,get_viewport_rect().size.y) chat_history.position = Vector2.ZERO #chat_history.set_anchors_preset(Control.PRESET_LEFT_WIDE) #chat_history.custom_minimum_size = Vector2(width,0) ChatDock.RIGHT: chat_history.custom_minimum_size = Vector2(500, get_viewport_rect().size.y - 265) chat_history.size = Vector2(500, 265) chat_history.position = Vector2(get_viewport_rect().size.x - 500, 0) #chat_history.set_anchors_preset(Control.PRESET_RIGHT_WIDE) #chat_history.custom_minimum_size = Vector2(width,0) ChatDock.TOP: chat_history.custom_minimum_size = Vector2(1550,265) chat_history.size = Vector2(1550,265) chat_history.position = Vector2.ZERO #chat_history.set_anchors_preset(Control.PRESET_TOP_WIDE) #chat_history.custom_minimum_size = Vector2(0,height) func _handle_chat(message: TwitchChatMessage) -> void: var badges_dict: Dictionary = await message.get_badges(Globals.twitcher.media) var badges: Array[SpriteFrames] = [] badges.assign(badges_dict.values()) var result_message: String = "" var badge_id: int = 0 for badge: SpriteFrames in badges: result_message += "[sprite id='b-%s']%s[/sprite]" % [badge_id, badge.resource_path] badge_id += 1 result_message += "[color=%s]%s[/color]" % [message.get_color(), message.chatter_user_name] match message.message_type: TwitchChatMessage.MessageType.text: result_message = await show_text(message, result_message) TwitchChatMessage.MessageType.power_ups_gigantified_emote: result_message = await show_text(message, result_message, 3) TwitchChatMessage.MessageType.channel_points_highlighted: result_message += "[bgcolor=#755ebc][color=#e9fffb]" result_message = await show_text(message, result_message) result_message += "[/color][/bgcolor]" TwitchChatMessage.MessageType.power_ups_message_effect: result_message += "[shake rate=20.0 level=5 connected=1]" result_message = await show_text(message, result_message) result_message += "[/shake]" append_message(result_message) func show_text(message: TwitchChatMessage, current_text: String, emote_scale: int = 1) -> String: await message.load_emotes_from_fragment(Globals.twitcher.media) var frag_id: int = 0 for fragment: TwitchChatMessage.Fragment in message.message.fragments: frag_id += 1 match fragment.type: TwitchChatMessage.FragmentType.text: current_text += fragment.text TwitchChatMessage.FragmentType.cheermote: var cheermote_scale: StringName = TwitchCheermoteDefinition.SCALE_MAP.get(emote_scale, TwitchCheermoteDefinition.SCALE_1) var cheermote: SpriteFrames = await fragment.cheermote.get_sprite_frames(Globals.twitcher.media, cheermote_scale) current_text += "[sprite id='f-%s']%s[/sprite]" % [frag_id, cheermote.resource_path] TwitchChatMessage.FragmentType.emote: var emote: SpriteFrames = await fragment.emote.get_sprite_frames(Globals.twitcher.media, emote_scale) current_text += "[sprite id='f-%s']%s[/sprite]" % [frag_id, emote.resource_path] TwitchChatMessage.FragmentType.mention: current_text += "[color=%s]@%s[/color]" % ["%00a0b6", fragment.mention.user_name] return current_text func append_message(msg: String) -> void: var cm: RichTextLabel = RichTextLabel.new() cm.bbcode_enabled = true cm.fit_content = true var se: SpriteFrameEffect = SpriteFrameEffect.new() cm.install_effect(se) %History.add_child(cm) msg = se.prepare_message(msg, cm) cm.text = _get_time() + " " + msg _clean_old_messages() await get_tree().process_frame var rect = cm.get_rect() %ChatHistory.set_deferred("scroll_vertical",rect.position.y + rect.size.y) func _clean_old_messages() -> void: var child_count := %ChatHistory.get_child_count() if child_count < 1000: return for i in child_count - 1000: %ChatHistory.get_child(i).queue_free() func _get_time() -> String: var time: Dictionary = Time.get_time_dict_from_system() var pm := false if time["hour"] >= 12: pm = true if time["hour"] > 12: time["hour"] -= 12 return "%02d:%02d%s" % [time["hour"], time["minute"], "PM" if pm else "AM"]