Compare commits
19 commits
76ba9536b7
...
199f2cdc9d
| Author | SHA1 | Date | |
|---|---|---|---|
| 199f2cdc9d | |||
| ba537bc791 | |||
| 73615a9bb4 | |||
| 5f8df9bf7b | |||
| 4e808314d2 | |||
| 689dcdc092 | |||
| 948fb00405 | |||
| 09dd6cb2e2 | |||
| feba26839b | |||
| 54901a14b9 | |||
| 9206793ebc | |||
| d44f1dbfb5 | |||
| e7a1732b0f | |||
| 6cccc36ecd | |||
| b52f62cc59 | |||
| b033741431 | |||
| e02daac0ff | |||
| 3804940b22 | |||
| e4637479e9 |
74 changed files with 2296 additions and 69 deletions
5
UI/Alerts/alert.gd
Normal file
5
UI/Alerts/alert.gd
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
extends Control
|
||||||
|
class_name Alert
|
||||||
|
|
||||||
|
func dispose() -> void:
|
||||||
|
queue_free()
|
||||||
1
UI/Alerts/alert.gd.uid
Normal file
1
UI/Alerts/alert.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://bw0rk6o7xj67e
|
||||||
26
UI/Alerts/cheer_alert.gd
Normal file
26
UI/Alerts/cheer_alert.gd
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
@tool
|
||||||
|
extends Alert
|
||||||
|
class_name CheerAlert
|
||||||
|
|
||||||
|
@onready var sub_text: Label = %SubText
|
||||||
|
@onready var main_text: Label = %MainText
|
||||||
|
@onready var message_text: Label = %MessageText
|
||||||
|
@onready var timeline: AnimationPlayer = %Timeline
|
||||||
|
|
||||||
|
var _chatter: String = "None"
|
||||||
|
var _msg: String = ""
|
||||||
|
var _bits: int = 0
|
||||||
|
|
||||||
|
func setup(chatter: String, bits: int, message: String) -> void:
|
||||||
|
_chatter = chatter
|
||||||
|
_bits = bits
|
||||||
|
_msg = message
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _ready() -> void:
|
||||||
|
main_text.text = _chatter
|
||||||
|
sub_text.text = "x%d bits" % _bits
|
||||||
|
message_text.text = _msg
|
||||||
|
|
||||||
|
if Engine.is_editor_hint(): return
|
||||||
|
timeline.play(&"default")
|
||||||
1
UI/Alerts/cheer_alert.gd.uid
Normal file
1
UI/Alerts/cheer_alert.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://crl8eyb3nahln
|
||||||
278
UI/Alerts/cheer_alert.tscn
Normal file
278
UI/Alerts/cheer_alert.tscn
Normal file
|
|
@ -0,0 +1,278 @@
|
||||||
|
[gd_scene format=3 uid="uid://d05mpml5k78u6"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://ivx7m2bfysip" path="res://addons/gde_gozen/video_playback.gd" id="1_7rajh"]
|
||||||
|
[ext_resource type="Script" uid="uid://crl8eyb3nahln" path="res://UI/Alerts/cheer_alert.gd" id="1_eam5w"]
|
||||||
|
[ext_resource type="FontFile" uid="uid://cx1a4aqqxhsrn" path="res://UI/assets/neon-wave-theme/polentical_neon/Polentical Neon Italic.ttf" id="2_eam5w"]
|
||||||
|
[ext_resource type="FontFile" uid="uid://c30qqiv6sqheh" path="res://UI/assets/fonts/rage.woff2" id="3_vhkt3"]
|
||||||
|
|
||||||
|
[sub_resource type="LabelSettings" id="LabelSettings_t8pat"]
|
||||||
|
font = ExtResource("3_vhkt3")
|
||||||
|
font_size = 48
|
||||||
|
font_color = Color(0, 1, 1, 1)
|
||||||
|
stacked_shadow_count = 2
|
||||||
|
stacked_shadow_0/offset = Vector2(2, 2)
|
||||||
|
stacked_shadow_0/color = Color(0.35822138, 0.0011343455, 0.8658768, 1)
|
||||||
|
stacked_shadow_0/outline_size = 3
|
||||||
|
stacked_shadow_1/offset = Vector2(4, 4)
|
||||||
|
stacked_shadow_1/color = Color(1, 0.5023, 0.43550968, 1)
|
||||||
|
stacked_shadow_1/outline_size = 5
|
||||||
|
|
||||||
|
[sub_resource type="LabelSettings" id="LabelSettings_jsg8g"]
|
||||||
|
font = ExtResource("2_eam5w")
|
||||||
|
font_size = 60
|
||||||
|
font_color = Color(0.99999994, 0.6120906, 0.16155985, 1)
|
||||||
|
stacked_shadow_count = 4
|
||||||
|
stacked_shadow_0/offset = Vector2(2, 2)
|
||||||
|
stacked_shadow_0/color = Color(0.5568628, 0.003921569, 1, 1)
|
||||||
|
stacked_shadow_0/outline_size = 2
|
||||||
|
stacked_shadow_1/offset = Vector2(3, 3)
|
||||||
|
stacked_shadow_1/color = Color(0.9411765, 0.003921569, 1, 1)
|
||||||
|
stacked_shadow_1/outline_size = 2
|
||||||
|
stacked_shadow_2/offset = Vector2(4, 4)
|
||||||
|
stacked_shadow_2/color = Color(0.9843137, 0.25882354, 0.7254902, 1)
|
||||||
|
stacked_shadow_2/outline_size = 2
|
||||||
|
stacked_shadow_3/offset = Vector2(5, 5)
|
||||||
|
stacked_shadow_3/color = Color(0.99215686, 0.46666667, 0.8039216, 1)
|
||||||
|
stacked_shadow_3/outline_size = 2
|
||||||
|
|
||||||
|
[sub_resource type="LabelSettings" id="LabelSettings_vhkt3"]
|
||||||
|
font_size = 24
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_jsg8g"]
|
||||||
|
length = 0.001
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("SubText:modulate")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"update": 0,
|
||||||
|
"values": [Color(1, 1, 1, 0)]
|
||||||
|
}
|
||||||
|
tracks/1/type = "value"
|
||||||
|
tracks/1/imported = false
|
||||||
|
tracks/1/enabled = true
|
||||||
|
tracks/1/path = NodePath("MainText:modulate")
|
||||||
|
tracks/1/interp = 1
|
||||||
|
tracks/1/loop_wrap = true
|
||||||
|
tracks/1/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"update": 0,
|
||||||
|
"values": [Color(1, 1, 1, 0)]
|
||||||
|
}
|
||||||
|
tracks/2/type = "value"
|
||||||
|
tracks/2/imported = false
|
||||||
|
tracks/2/enabled = true
|
||||||
|
tracks/2/path = NodePath("MessageText:modulate")
|
||||||
|
tracks/2/interp = 1
|
||||||
|
tracks/2/loop_wrap = true
|
||||||
|
tracks/2/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"update": 0,
|
||||||
|
"values": [Color(1, 1, 1, 0)]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_t8pat"]
|
||||||
|
resource_name = "default"
|
||||||
|
length = 10.0
|
||||||
|
tracks/0/type = "method"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("Background")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"values": [{
|
||||||
|
"args": [],
|
||||||
|
"method": &"play"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
tracks/1/type = "method"
|
||||||
|
tracks/1/imported = false
|
||||||
|
tracks/1/enabled = true
|
||||||
|
tracks/1/path = NodePath("Icon")
|
||||||
|
tracks/1/interp = 1
|
||||||
|
tracks/1/loop_wrap = true
|
||||||
|
tracks/1/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"values": [{
|
||||||
|
"args": [],
|
||||||
|
"method": &"play"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
tracks/2/type = "value"
|
||||||
|
tracks/2/imported = false
|
||||||
|
tracks/2/enabled = true
|
||||||
|
tracks/2/path = NodePath("SubText:modulate")
|
||||||
|
tracks/2/interp = 1
|
||||||
|
tracks/2/loop_wrap = true
|
||||||
|
tracks/2/keys = {
|
||||||
|
"times": PackedFloat32Array(0, 3, 4, 9, 10),
|
||||||
|
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
|
||||||
|
"update": 0,
|
||||||
|
"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 0), Color(1, 1, 1, 1), Color(1, 1, 1, 1), Color(1, 1, 1, 0)]
|
||||||
|
}
|
||||||
|
tracks/3/type = "value"
|
||||||
|
tracks/3/imported = false
|
||||||
|
tracks/3/enabled = true
|
||||||
|
tracks/3/path = NodePath("MainText:modulate")
|
||||||
|
tracks/3/interp = 1
|
||||||
|
tracks/3/loop_wrap = true
|
||||||
|
tracks/3/keys = {
|
||||||
|
"times": PackedFloat32Array(0, 2, 3, 9, 10),
|
||||||
|
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
|
||||||
|
"update": 0,
|
||||||
|
"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 0), Color(1, 1, 1, 1), Color(1, 1, 1, 1), Color(1, 1, 1, 0)]
|
||||||
|
}
|
||||||
|
tracks/4/type = "method"
|
||||||
|
tracks/4/imported = false
|
||||||
|
tracks/4/enabled = true
|
||||||
|
tracks/4/path = NodePath(".")
|
||||||
|
tracks/4/interp = 1
|
||||||
|
tracks/4/loop_wrap = true
|
||||||
|
tracks/4/keys = {
|
||||||
|
"times": PackedFloat32Array(10),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"values": [{
|
||||||
|
"args": [],
|
||||||
|
"method": &"dispose"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
tracks/5/type = "value"
|
||||||
|
tracks/5/imported = false
|
||||||
|
tracks/5/enabled = true
|
||||||
|
tracks/5/path = NodePath("MessageText:modulate")
|
||||||
|
tracks/5/interp = 1
|
||||||
|
tracks/5/loop_wrap = true
|
||||||
|
tracks/5/keys = {
|
||||||
|
"times": PackedFloat32Array(0, 4, 5, 9, 10),
|
||||||
|
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
|
||||||
|
"update": 0,
|
||||||
|
"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 0), Color(1, 1, 1, 1), Color(1, 1, 1, 1), Color(1, 1, 1, 0)]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="AnimationLibrary" id="AnimationLibrary_jsg8g"]
|
||||||
|
_data = {
|
||||||
|
&"RESET": SubResource("Animation_jsg8g"),
|
||||||
|
&"default": SubResource("Animation_t8pat")
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="CheerAlert" type="Control" unique_id=95763662]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_eam5w")
|
||||||
|
|
||||||
|
[node name="Background" type="Control" parent="." unique_id=939332259]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(960, 540)
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -480.0
|
||||||
|
offset_top = -270.0
|
||||||
|
offset_right = 480.0
|
||||||
|
offset_bottom = 270.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_7rajh")
|
||||||
|
path = "res://UI/assets/video/Backgrounds/Lightning-Synthwave.webm"
|
||||||
|
metadata/_custom_type_script = "uid://ivx7m2bfysip"
|
||||||
|
|
||||||
|
[node name="Icon" type="Control" parent="." unique_id=823113899]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(470, 260)
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -195.0
|
||||||
|
offset_top = -303.0
|
||||||
|
offset_right = 275.0
|
||||||
|
offset_bottom = -43.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_7rajh")
|
||||||
|
path = "res://UI/assets/video/Backgrounds/Bits-Synthwave.webm"
|
||||||
|
enable_audio = false
|
||||||
|
metadata/_custom_type_script = "uid://ivx7m2bfysip"
|
||||||
|
|
||||||
|
[node name="SubText" type="Label" parent="." unique_id=1794185310]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
modulate = Color(1, 1, 1, 0)
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -183.0
|
||||||
|
offset_top = -85.0
|
||||||
|
offset_right = 183.0
|
||||||
|
offset_bottom = -25.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
text = "x40 Bits"
|
||||||
|
label_settings = SubResource("LabelSettings_t8pat")
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="MainText" type="Label" parent="." unique_id=757351879]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
modulate = Color(1, 1, 1, 0)
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -145.0
|
||||||
|
offset_top = -37.5
|
||||||
|
offset_right = 145.0
|
||||||
|
offset_bottom = 37.5
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
text = "None"
|
||||||
|
label_settings = SubResource("LabelSettings_jsg8g")
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="MessageText" type="Label" parent="." unique_id=79076647]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
modulate = Color(1, 1, 1, 0)
|
||||||
|
custom_minimum_size = Vector2(1000, 200)
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -500.0
|
||||||
|
offset_top = 55.0
|
||||||
|
offset_right = 500.0
|
||||||
|
offset_bottom = 255.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
text = "Born to late to explore Earth, born to early to explore the universe"
|
||||||
|
label_settings = SubResource("LabelSettings_vhkt3")
|
||||||
|
horizontal_alignment = 1
|
||||||
|
autowrap_mode = 2
|
||||||
|
max_lines_visible = 5
|
||||||
|
|
||||||
|
[node name="Timeline" type="AnimationPlayer" parent="." unique_id=1438475424]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
libraries/ = SubResource("AnimationLibrary_jsg8g")
|
||||||
16
UI/Alerts/follow_alert.gd
Normal file
16
UI/Alerts/follow_alert.gd
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
@tool
|
||||||
|
extends Alert
|
||||||
|
class_name FollowAlert
|
||||||
|
@onready var main_text: Label = %MainText
|
||||||
|
@onready var timeline: AnimationPlayer = %Timeline
|
||||||
|
|
||||||
|
var _chatter: String = "None"
|
||||||
|
|
||||||
|
func setup(chatter: String) -> void:
|
||||||
|
_chatter = chatter
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _ready() -> void:
|
||||||
|
main_text.text = _chatter
|
||||||
|
if Engine.is_editor_hint(): return
|
||||||
|
timeline.play(&"default")
|
||||||
1
UI/Alerts/follow_alert.gd.uid
Normal file
1
UI/Alerts/follow_alert.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://cdfp46glq557p
|
||||||
226
UI/Alerts/follow_alert.tscn
Normal file
226
UI/Alerts/follow_alert.tscn
Normal file
|
|
@ -0,0 +1,226 @@
|
||||||
|
[gd_scene format=3 uid="uid://dr2di6iv0mdkh"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://cdfp46glq557p" path="res://UI/Alerts/follow_alert.gd" id="1_44jhq"]
|
||||||
|
[ext_resource type="Script" uid="uid://ivx7m2bfysip" path="res://addons/gde_gozen/video_playback.gd" id="1_86a2m"]
|
||||||
|
[ext_resource type="FontFile" uid="uid://cx1a4aqqxhsrn" path="res://UI/assets/neon-wave-theme/polentical_neon/Polentical Neon Italic.ttf" id="3_t8pat"]
|
||||||
|
|
||||||
|
[sub_resource type="LabelSettings" id="LabelSettings_t8pat"]
|
||||||
|
font_size = 48
|
||||||
|
font_color = Color(0, 1, 1, 1)
|
||||||
|
stacked_shadow_count = 2
|
||||||
|
stacked_shadow_0/offset = Vector2(2, 2)
|
||||||
|
stacked_shadow_0/color = Color(0.35822138, 0.0011343455, 0.8658768, 1)
|
||||||
|
stacked_shadow_0/outline_size = 3
|
||||||
|
stacked_shadow_1/offset = Vector2(4, 4)
|
||||||
|
stacked_shadow_1/color = Color(1, 0.5023, 0.43550968, 1)
|
||||||
|
stacked_shadow_1/outline_size = 5
|
||||||
|
|
||||||
|
[sub_resource type="LabelSettings" id="LabelSettings_jsg8g"]
|
||||||
|
font = ExtResource("3_t8pat")
|
||||||
|
font_size = 60
|
||||||
|
font_color = Color(0.99999994, 0.6120906, 0.16155985, 1)
|
||||||
|
stacked_shadow_count = 4
|
||||||
|
stacked_shadow_0/offset = Vector2(2, 2)
|
||||||
|
stacked_shadow_0/color = Color(0.5568628, 0.003921569, 1, 1)
|
||||||
|
stacked_shadow_0/outline_size = 2
|
||||||
|
stacked_shadow_1/offset = Vector2(3, 3)
|
||||||
|
stacked_shadow_1/color = Color(0.9411765, 0.003921569, 1, 1)
|
||||||
|
stacked_shadow_1/outline_size = 2
|
||||||
|
stacked_shadow_2/offset = Vector2(4, 4)
|
||||||
|
stacked_shadow_2/color = Color(0.9843137, 0.25882354, 0.7254902, 1)
|
||||||
|
stacked_shadow_2/outline_size = 2
|
||||||
|
stacked_shadow_3/offset = Vector2(5, 5)
|
||||||
|
stacked_shadow_3/color = Color(0.99215686, 0.46666667, 0.8039216, 1)
|
||||||
|
stacked_shadow_3/outline_size = 2
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_jsg8g"]
|
||||||
|
length = 0.001
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("SubText:modulate")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"update": 0,
|
||||||
|
"values": [Color(1, 1, 1, 0)]
|
||||||
|
}
|
||||||
|
tracks/1/type = "value"
|
||||||
|
tracks/1/imported = false
|
||||||
|
tracks/1/enabled = true
|
||||||
|
tracks/1/path = NodePath("MainText:modulate")
|
||||||
|
tracks/1/interp = 1
|
||||||
|
tracks/1/loop_wrap = true
|
||||||
|
tracks/1/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"update": 0,
|
||||||
|
"values": [Color(1, 1, 1, 0)]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_t8pat"]
|
||||||
|
resource_name = "default"
|
||||||
|
length = 10.0
|
||||||
|
tracks/0/type = "method"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("Background")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"values": [{
|
||||||
|
"args": [],
|
||||||
|
"method": &"play"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
tracks/1/type = "method"
|
||||||
|
tracks/1/imported = false
|
||||||
|
tracks/1/enabled = true
|
||||||
|
tracks/1/path = NodePath("Icon")
|
||||||
|
tracks/1/interp = 1
|
||||||
|
tracks/1/loop_wrap = true
|
||||||
|
tracks/1/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"values": [{
|
||||||
|
"args": [],
|
||||||
|
"method": &"play"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
tracks/2/type = "value"
|
||||||
|
tracks/2/imported = false
|
||||||
|
tracks/2/enabled = true
|
||||||
|
tracks/2/path = NodePath("SubText:modulate")
|
||||||
|
tracks/2/interp = 1
|
||||||
|
tracks/2/loop_wrap = true
|
||||||
|
tracks/2/keys = {
|
||||||
|
"times": PackedFloat32Array(0, 5, 6, 9, 10),
|
||||||
|
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
|
||||||
|
"update": 0,
|
||||||
|
"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 0), Color(1, 1, 1, 1), Color(1, 1, 1, 1), Color(1, 1, 1, 0)]
|
||||||
|
}
|
||||||
|
tracks/3/type = "value"
|
||||||
|
tracks/3/imported = false
|
||||||
|
tracks/3/enabled = true
|
||||||
|
tracks/3/path = NodePath("MainText:modulate")
|
||||||
|
tracks/3/interp = 1
|
||||||
|
tracks/3/loop_wrap = true
|
||||||
|
tracks/3/keys = {
|
||||||
|
"times": PackedFloat32Array(0, 3, 4, 9, 10),
|
||||||
|
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
|
||||||
|
"update": 0,
|
||||||
|
"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 0), Color(1, 1, 1, 1), Color(1, 1, 1, 1), Color(1, 1, 1, 0)]
|
||||||
|
}
|
||||||
|
tracks/4/type = "method"
|
||||||
|
tracks/4/imported = false
|
||||||
|
tracks/4/enabled = true
|
||||||
|
tracks/4/path = NodePath(".")
|
||||||
|
tracks/4/interp = 1
|
||||||
|
tracks/4/loop_wrap = true
|
||||||
|
tracks/4/keys = {
|
||||||
|
"times": PackedFloat32Array(10),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"values": [{
|
||||||
|
"args": [],
|
||||||
|
"method": &"dispose"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="AnimationLibrary" id="AnimationLibrary_jsg8g"]
|
||||||
|
_data = {
|
||||||
|
&"RESET": SubResource("Animation_jsg8g"),
|
||||||
|
&"default": SubResource("Animation_t8pat")
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="FollowAlert" type="Control" unique_id=95763662]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_44jhq")
|
||||||
|
|
||||||
|
[node name="Background" type="Control" parent="." unique_id=939332259]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(960, 540)
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -480.0
|
||||||
|
offset_top = -270.0
|
||||||
|
offset_right = 480.0
|
||||||
|
offset_bottom = 270.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_86a2m")
|
||||||
|
path = "res://UI/assets/video/Backgrounds/Stripes-Synthwave.webm"
|
||||||
|
metadata/_custom_type_script = "uid://ivx7m2bfysip"
|
||||||
|
|
||||||
|
[node name="Icon" type="Control" parent="." unique_id=823113899]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(470, 260)
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -195.0
|
||||||
|
offset_top = -303.0
|
||||||
|
offset_right = 275.0
|
||||||
|
offset_bottom = -43.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_86a2m")
|
||||||
|
path = "res://UI/assets/video/Icons/Joystick-Synthwave.webm"
|
||||||
|
enable_audio = false
|
||||||
|
metadata/_custom_type_script = "uid://ivx7m2bfysip"
|
||||||
|
|
||||||
|
[node name="SubText" type="Label" parent="." unique_id=1794185310]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
modulate = Color(1, 1, 1, 0)
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -183.0
|
||||||
|
offset_top = -85.0
|
||||||
|
offset_right = 183.0
|
||||||
|
offset_bottom = -25.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
text = "New Follower"
|
||||||
|
label_settings = SubResource("LabelSettings_t8pat")
|
||||||
|
|
||||||
|
[node name="MainText" type="Label" parent="." unique_id=757351879]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
modulate = Color(1, 1, 1, 0)
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -145.0
|
||||||
|
offset_top = -37.5
|
||||||
|
offset_right = 145.0
|
||||||
|
offset_bottom = 37.5
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
text = "None"
|
||||||
|
label_settings = SubResource("LabelSettings_jsg8g")
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="Timeline" type="AnimationPlayer" parent="." unique_id=1438475424]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
libraries/ = SubResource("AnimationLibrary_jsg8g")
|
||||||
22
UI/Alerts/raid_alert.gd
Normal file
22
UI/Alerts/raid_alert.gd
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
@tool
|
||||||
|
extends Alert
|
||||||
|
class_name RaidAlert
|
||||||
|
|
||||||
|
@onready var sub_text: Label = %SubText
|
||||||
|
@onready var main_text: Label = %MainText
|
||||||
|
@onready var timeline: AnimationPlayer = %Timeline
|
||||||
|
|
||||||
|
var _chatter: String = "None"
|
||||||
|
var _raiders: int = 0
|
||||||
|
|
||||||
|
func setup(chatter: String, raiders: int) -> void:
|
||||||
|
_chatter = chatter
|
||||||
|
_raiders = raiders
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _ready() -> void:
|
||||||
|
main_text.text = _chatter
|
||||||
|
sub_text.text = "Raid x%d" % _raiders
|
||||||
|
|
||||||
|
if Engine.is_editor_hint(): return
|
||||||
|
timeline.play(&"default")
|
||||||
1
UI/Alerts/raid_alert.gd.uid
Normal file
1
UI/Alerts/raid_alert.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://cns0ihwkp2i1c
|
||||||
229
UI/Alerts/raid_alert.tscn
Normal file
229
UI/Alerts/raid_alert.tscn
Normal file
|
|
@ -0,0 +1,229 @@
|
||||||
|
[gd_scene format=3 uid="uid://b6jis61uxnhf3"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://cns0ihwkp2i1c" path="res://UI/Alerts/raid_alert.gd" id="1_ur8rv"]
|
||||||
|
[ext_resource type="Script" uid="uid://ivx7m2bfysip" path="res://addons/gde_gozen/video_playback.gd" id="1_yqbii"]
|
||||||
|
[ext_resource type="FontFile" uid="uid://cx1a4aqqxhsrn" path="res://UI/assets/neon-wave-theme/polentical_neon/Polentical Neon Italic.ttf" id="2_ur8rv"]
|
||||||
|
[ext_resource type="FontFile" uid="uid://c30qqiv6sqheh" path="res://UI/assets/fonts/rage.woff2" id="3_6v7ty"]
|
||||||
|
|
||||||
|
[sub_resource type="LabelSettings" id="LabelSettings_t8pat"]
|
||||||
|
font = ExtResource("3_6v7ty")
|
||||||
|
font_size = 64
|
||||||
|
font_color = Color(0.60239375, 0.9999997, 0.3363843, 1)
|
||||||
|
stacked_shadow_count = 2
|
||||||
|
stacked_shadow_0/offset = Vector2(2, 2)
|
||||||
|
stacked_shadow_0/color = Color(0.35822138, 0.0011343455, 0.8658768, 1)
|
||||||
|
stacked_shadow_0/outline_size = 3
|
||||||
|
stacked_shadow_1/offset = Vector2(4, 4)
|
||||||
|
stacked_shadow_1/color = Color(1, 0.5023, 0.43550968, 1)
|
||||||
|
stacked_shadow_1/outline_size = 5
|
||||||
|
|
||||||
|
[sub_resource type="LabelSettings" id="LabelSettings_jsg8g"]
|
||||||
|
font = ExtResource("2_ur8rv")
|
||||||
|
font_size = 60
|
||||||
|
font_color = Color(0.99999994, 0.6120906, 0.16155985, 1)
|
||||||
|
stacked_shadow_count = 4
|
||||||
|
stacked_shadow_0/offset = Vector2(2, 2)
|
||||||
|
stacked_shadow_0/color = Color(0.5568628, 0.003921569, 1, 1)
|
||||||
|
stacked_shadow_0/outline_size = 2
|
||||||
|
stacked_shadow_1/offset = Vector2(3, 3)
|
||||||
|
stacked_shadow_1/color = Color(0.9411765, 0.003921569, 1, 1)
|
||||||
|
stacked_shadow_1/outline_size = 2
|
||||||
|
stacked_shadow_2/offset = Vector2(4, 4)
|
||||||
|
stacked_shadow_2/color = Color(0.9843137, 0.25882354, 0.7254902, 1)
|
||||||
|
stacked_shadow_2/outline_size = 2
|
||||||
|
stacked_shadow_3/offset = Vector2(5, 5)
|
||||||
|
stacked_shadow_3/color = Color(0.99215686, 0.46666667, 0.8039216, 1)
|
||||||
|
stacked_shadow_3/outline_size = 2
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_jsg8g"]
|
||||||
|
length = 0.001
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("SubText:modulate")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"update": 0,
|
||||||
|
"values": [Color(1, 1, 1, 0)]
|
||||||
|
}
|
||||||
|
tracks/1/type = "value"
|
||||||
|
tracks/1/imported = false
|
||||||
|
tracks/1/enabled = true
|
||||||
|
tracks/1/path = NodePath("MainText:modulate")
|
||||||
|
tracks/1/interp = 1
|
||||||
|
tracks/1/loop_wrap = true
|
||||||
|
tracks/1/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"update": 0,
|
||||||
|
"values": [Color(1, 1, 1, 0)]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_t8pat"]
|
||||||
|
resource_name = "default"
|
||||||
|
length = 10.0
|
||||||
|
tracks/0/type = "method"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("Background")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"values": [{
|
||||||
|
"args": [],
|
||||||
|
"method": &"play"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
tracks/1/type = "method"
|
||||||
|
tracks/1/imported = false
|
||||||
|
tracks/1/enabled = true
|
||||||
|
tracks/1/path = NodePath("Icon")
|
||||||
|
tracks/1/interp = 1
|
||||||
|
tracks/1/loop_wrap = true
|
||||||
|
tracks/1/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"values": [{
|
||||||
|
"args": [],
|
||||||
|
"method": &"play"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
tracks/2/type = "value"
|
||||||
|
tracks/2/imported = false
|
||||||
|
tracks/2/enabled = true
|
||||||
|
tracks/2/path = NodePath("SubText:modulate")
|
||||||
|
tracks/2/interp = 1
|
||||||
|
tracks/2/loop_wrap = true
|
||||||
|
tracks/2/keys = {
|
||||||
|
"times": PackedFloat32Array(0, 5, 6, 9, 10),
|
||||||
|
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
|
||||||
|
"update": 0,
|
||||||
|
"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 0), Color(1, 1, 1, 1), Color(1, 1, 1, 1), Color(1, 1, 1, 0)]
|
||||||
|
}
|
||||||
|
tracks/3/type = "value"
|
||||||
|
tracks/3/imported = false
|
||||||
|
tracks/3/enabled = true
|
||||||
|
tracks/3/path = NodePath("MainText:modulate")
|
||||||
|
tracks/3/interp = 1
|
||||||
|
tracks/3/loop_wrap = true
|
||||||
|
tracks/3/keys = {
|
||||||
|
"times": PackedFloat32Array(0, 3, 4, 9, 10),
|
||||||
|
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
|
||||||
|
"update": 0,
|
||||||
|
"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 0), Color(1, 1, 1, 1), Color(1, 1, 1, 1), Color(1, 1, 1, 0)]
|
||||||
|
}
|
||||||
|
tracks/4/type = "method"
|
||||||
|
tracks/4/imported = false
|
||||||
|
tracks/4/enabled = true
|
||||||
|
tracks/4/path = NodePath(".")
|
||||||
|
tracks/4/interp = 1
|
||||||
|
tracks/4/loop_wrap = true
|
||||||
|
tracks/4/keys = {
|
||||||
|
"times": PackedFloat32Array(10),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"values": [{
|
||||||
|
"args": [],
|
||||||
|
"method": &"dispose"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="AnimationLibrary" id="AnimationLibrary_jsg8g"]
|
||||||
|
_data = {
|
||||||
|
&"RESET": SubResource("Animation_jsg8g"),
|
||||||
|
&"default": SubResource("Animation_t8pat")
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="RaidAlert" type="Control" unique_id=95763662]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_ur8rv")
|
||||||
|
|
||||||
|
[node name="Background" type="Control" parent="." unique_id=939332259]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(960, 540)
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -480.0
|
||||||
|
offset_top = -270.0
|
||||||
|
offset_right = 480.0
|
||||||
|
offset_bottom = 270.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_yqbii")
|
||||||
|
path = "res://UI/assets/video/Backgrounds/Grid-Synthwave.webm"
|
||||||
|
metadata/_custom_type_script = "uid://ivx7m2bfysip"
|
||||||
|
|
||||||
|
[node name="Icon" type="Control" parent="." unique_id=823113899]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(470, 260)
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -195.0
|
||||||
|
offset_top = -303.0
|
||||||
|
offset_right = 275.0
|
||||||
|
offset_bottom = -43.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_yqbii")
|
||||||
|
path = "res://UI/assets/video/Icons/Computer-Synthwave.webm"
|
||||||
|
enable_audio = false
|
||||||
|
metadata/_custom_type_script = "uid://ivx7m2bfysip"
|
||||||
|
|
||||||
|
[node name="SubText" type="Label" parent="." unique_id=1794185310]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
modulate = Color(1, 1, 1, 0)
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -183.0
|
||||||
|
offset_top = -110.0
|
||||||
|
offset_right = 183.0
|
||||||
|
offset_bottom = -18.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
text = "Raid x10"
|
||||||
|
label_settings = SubResource("LabelSettings_t8pat")
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="MainText" type="Label" parent="." unique_id=757351879]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
modulate = Color(1, 1, 1, 0)
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -145.0
|
||||||
|
offset_top = -37.5
|
||||||
|
offset_right = 145.0
|
||||||
|
offset_bottom = 37.5
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
text = "None"
|
||||||
|
label_settings = SubResource("LabelSettings_jsg8g")
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="Timeline" type="AnimationPlayer" parent="." unique_id=1438475424]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
libraries/ = SubResource("AnimationLibrary_jsg8g")
|
||||||
39
UI/Alerts/subscriber_alert.gd
Normal file
39
UI/Alerts/subscriber_alert.gd
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
@tool
|
||||||
|
extends Alert
|
||||||
|
class_name SubscriberAlert
|
||||||
|
|
||||||
|
@onready var sub_text: Label = %SubText
|
||||||
|
@onready var main_text: Label = %MainText
|
||||||
|
@onready var message_text: Label = %MessageText
|
||||||
|
@onready var timeline: AnimationPlayer = %Timeline
|
||||||
|
|
||||||
|
var _chatter: String = "None"
|
||||||
|
var _msg: String = ""
|
||||||
|
var _months: int = 0
|
||||||
|
var _prime: bool = false
|
||||||
|
var _tier: int = 1
|
||||||
|
|
||||||
|
func setup(chatter: String, months: int, prime: bool, tier: int, message: String) -> void:
|
||||||
|
_chatter = chatter
|
||||||
|
_months = months
|
||||||
|
_msg = message
|
||||||
|
_prime = prime
|
||||||
|
_tier = tier
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _ready() -> void:
|
||||||
|
main_text.text = _chatter
|
||||||
|
if _months <= 1:
|
||||||
|
if _prime:
|
||||||
|
sub_text.text = "New Prime Sub"
|
||||||
|
else:
|
||||||
|
sub_text.text = "New Teir %d Sub" % _tier
|
||||||
|
else:
|
||||||
|
if _prime:
|
||||||
|
sub_text.text = "Prime Resub x%d" % _months
|
||||||
|
else:
|
||||||
|
sub_text.text = "Teir %d Resub x%d" % [_tier, _months]
|
||||||
|
message_text.text = _msg
|
||||||
|
|
||||||
|
if Engine.is_editor_hint(): return
|
||||||
|
timeline.play(&"default")
|
||||||
1
UI/Alerts/subscriber_alert.gd.uid
Normal file
1
UI/Alerts/subscriber_alert.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://c6byqfgqyxfbh
|
||||||
278
UI/Alerts/subscriber_alert.tscn
Normal file
278
UI/Alerts/subscriber_alert.tscn
Normal file
|
|
@ -0,0 +1,278 @@
|
||||||
|
[gd_scene format=3 uid="uid://b3o8lxueafbqq"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://ivx7m2bfysip" path="res://addons/gde_gozen/video_playback.gd" id="1_b3tp1"]
|
||||||
|
[ext_resource type="Script" uid="uid://c6byqfgqyxfbh" path="res://UI/Alerts/subscriber_alert.gd" id="1_f1hvy"]
|
||||||
|
[ext_resource type="FontFile" uid="uid://cx1a4aqqxhsrn" path="res://UI/assets/neon-wave-theme/polentical_neon/Polentical Neon Italic.ttf" id="2_38hii"]
|
||||||
|
[ext_resource type="FontFile" uid="uid://o4e6chcu01yx" path="res://UI/assets/fonts/Yellowtail.woff2" id="3_4l3sh"]
|
||||||
|
|
||||||
|
[sub_resource type="LabelSettings" id="LabelSettings_t8pat"]
|
||||||
|
font = ExtResource("3_4l3sh")
|
||||||
|
font_size = 64
|
||||||
|
font_color = Color(0, 1, 1, 1)
|
||||||
|
stacked_shadow_count = 2
|
||||||
|
stacked_shadow_0/offset = Vector2(2, 2)
|
||||||
|
stacked_shadow_0/color = Color(0.35822138, 0.0011343455, 0.8658768, 1)
|
||||||
|
stacked_shadow_0/outline_size = 3
|
||||||
|
stacked_shadow_1/offset = Vector2(4, 4)
|
||||||
|
stacked_shadow_1/color = Color(1, 0.5023, 0.43550968, 1)
|
||||||
|
stacked_shadow_1/outline_size = 5
|
||||||
|
|
||||||
|
[sub_resource type="LabelSettings" id="LabelSettings_jsg8g"]
|
||||||
|
font = ExtResource("2_38hii")
|
||||||
|
font_size = 60
|
||||||
|
font_color = Color(0.99999994, 0.6120906, 0.16155985, 1)
|
||||||
|
stacked_shadow_count = 4
|
||||||
|
stacked_shadow_0/offset = Vector2(2, 2)
|
||||||
|
stacked_shadow_0/color = Color(0.5568628, 0.003921569, 1, 1)
|
||||||
|
stacked_shadow_0/outline_size = 2
|
||||||
|
stacked_shadow_1/offset = Vector2(3, 3)
|
||||||
|
stacked_shadow_1/color = Color(0.9411765, 0.003921569, 1, 1)
|
||||||
|
stacked_shadow_1/outline_size = 2
|
||||||
|
stacked_shadow_2/offset = Vector2(4, 4)
|
||||||
|
stacked_shadow_2/color = Color(0.9843137, 0.25882354, 0.7254902, 1)
|
||||||
|
stacked_shadow_2/outline_size = 2
|
||||||
|
stacked_shadow_3/offset = Vector2(5, 5)
|
||||||
|
stacked_shadow_3/color = Color(0.99215686, 0.46666667, 0.8039216, 1)
|
||||||
|
stacked_shadow_3/outline_size = 2
|
||||||
|
|
||||||
|
[sub_resource type="LabelSettings" id="LabelSettings_dx50j"]
|
||||||
|
font_size = 24
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_jsg8g"]
|
||||||
|
length = 0.001
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("SubText:modulate")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"update": 0,
|
||||||
|
"values": [Color(1, 1, 1, 0)]
|
||||||
|
}
|
||||||
|
tracks/1/type = "value"
|
||||||
|
tracks/1/imported = false
|
||||||
|
tracks/1/enabled = true
|
||||||
|
tracks/1/path = NodePath("MainText:modulate")
|
||||||
|
tracks/1/interp = 1
|
||||||
|
tracks/1/loop_wrap = true
|
||||||
|
tracks/1/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"update": 0,
|
||||||
|
"values": [Color(1, 1, 1, 0)]
|
||||||
|
}
|
||||||
|
tracks/2/type = "value"
|
||||||
|
tracks/2/imported = false
|
||||||
|
tracks/2/enabled = true
|
||||||
|
tracks/2/path = NodePath("MessageText:modulate")
|
||||||
|
tracks/2/interp = 1
|
||||||
|
tracks/2/loop_wrap = true
|
||||||
|
tracks/2/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"update": 0,
|
||||||
|
"values": [Color(1, 1, 1, 0)]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_t8pat"]
|
||||||
|
resource_name = "default"
|
||||||
|
length = 10.0
|
||||||
|
tracks/0/type = "method"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("Background")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"values": [{
|
||||||
|
"args": [],
|
||||||
|
"method": &"play"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
tracks/1/type = "method"
|
||||||
|
tracks/1/imported = false
|
||||||
|
tracks/1/enabled = true
|
||||||
|
tracks/1/path = NodePath("Icon")
|
||||||
|
tracks/1/interp = 1
|
||||||
|
tracks/1/loop_wrap = true
|
||||||
|
tracks/1/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"values": [{
|
||||||
|
"args": [],
|
||||||
|
"method": &"play"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
tracks/2/type = "value"
|
||||||
|
tracks/2/imported = false
|
||||||
|
tracks/2/enabled = true
|
||||||
|
tracks/2/path = NodePath("SubText:modulate")
|
||||||
|
tracks/2/interp = 1
|
||||||
|
tracks/2/loop_wrap = true
|
||||||
|
tracks/2/keys = {
|
||||||
|
"times": PackedFloat32Array(0, 3, 4, 9, 10),
|
||||||
|
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
|
||||||
|
"update": 0,
|
||||||
|
"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 0), Color(1, 1, 1, 1), Color(1, 1, 1, 1), Color(1, 1, 1, 0)]
|
||||||
|
}
|
||||||
|
tracks/3/type = "value"
|
||||||
|
tracks/3/imported = false
|
||||||
|
tracks/3/enabled = true
|
||||||
|
tracks/3/path = NodePath("MainText:modulate")
|
||||||
|
tracks/3/interp = 1
|
||||||
|
tracks/3/loop_wrap = true
|
||||||
|
tracks/3/keys = {
|
||||||
|
"times": PackedFloat32Array(0, 2, 3, 9, 10),
|
||||||
|
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
|
||||||
|
"update": 0,
|
||||||
|
"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 0), Color(1, 1, 1, 1), Color(1, 1, 1, 1), Color(1, 1, 1, 0)]
|
||||||
|
}
|
||||||
|
tracks/4/type = "method"
|
||||||
|
tracks/4/imported = false
|
||||||
|
tracks/4/enabled = true
|
||||||
|
tracks/4/path = NodePath(".")
|
||||||
|
tracks/4/interp = 1
|
||||||
|
tracks/4/loop_wrap = true
|
||||||
|
tracks/4/keys = {
|
||||||
|
"times": PackedFloat32Array(10),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"values": [{
|
||||||
|
"args": [],
|
||||||
|
"method": &"dispose"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
tracks/5/type = "value"
|
||||||
|
tracks/5/imported = false
|
||||||
|
tracks/5/enabled = true
|
||||||
|
tracks/5/path = NodePath("MessageText:modulate")
|
||||||
|
tracks/5/interp = 1
|
||||||
|
tracks/5/loop_wrap = true
|
||||||
|
tracks/5/keys = {
|
||||||
|
"times": PackedFloat32Array(0, 4, 5, 9, 10),
|
||||||
|
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
|
||||||
|
"update": 0,
|
||||||
|
"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 0), Color(1, 1, 1, 1), Color(1, 1, 1, 1), Color(1, 1, 1, 0)]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="AnimationLibrary" id="AnimationLibrary_f1hvy"]
|
||||||
|
_data = {
|
||||||
|
&"RESET": SubResource("Animation_jsg8g"),
|
||||||
|
&"default": SubResource("Animation_t8pat")
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="SubscriberAlert" type="Control" unique_id=95763662]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_f1hvy")
|
||||||
|
|
||||||
|
[node name="Background" type="Control" parent="." unique_id=939332259]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(960, 540)
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -480.0
|
||||||
|
offset_top = -270.0
|
||||||
|
offset_right = 480.0
|
||||||
|
offset_bottom = 270.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_b3tp1")
|
||||||
|
path = "res://UI/assets/video/Backgrounds/Triangle-Synthwave.webm"
|
||||||
|
metadata/_custom_type_script = "uid://ivx7m2bfysip"
|
||||||
|
|
||||||
|
[node name="Icon" type="Control" parent="." unique_id=823113899]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(470, 260)
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -234.0
|
||||||
|
offset_top = -303.0
|
||||||
|
offset_right = 236.0
|
||||||
|
offset_bottom = -43.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_b3tp1")
|
||||||
|
path = "res://UI/assets/video/Icons/Hoverboard-Synthwave.webm"
|
||||||
|
enable_audio = false
|
||||||
|
metadata/_custom_type_script = "uid://ivx7m2bfysip"
|
||||||
|
|
||||||
|
[node name="SubText" type="Label" parent="." unique_id=1794185310]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
modulate = Color(1, 1, 1, 0)
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -183.0
|
||||||
|
offset_top = -85.0
|
||||||
|
offset_right = 183.0
|
||||||
|
offset_bottom = -25.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
text = "New Sub"
|
||||||
|
label_settings = SubResource("LabelSettings_t8pat")
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="MainText" type="Label" parent="." unique_id=757351879]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
modulate = Color(1, 1, 1, 0)
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -145.0
|
||||||
|
offset_top = -37.5
|
||||||
|
offset_right = 145.0
|
||||||
|
offset_bottom = 37.5
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
text = "None"
|
||||||
|
label_settings = SubResource("LabelSettings_jsg8g")
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="MessageText" type="Label" parent="." unique_id=4513558]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
modulate = Color(1, 1, 1, 0)
|
||||||
|
custom_minimum_size = Vector2(1000, 200)
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -500.0
|
||||||
|
offset_top = 55.0
|
||||||
|
offset_right = 500.0
|
||||||
|
offset_bottom = 255.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
text = "Born to late to explore Earth, born to early to explore the universe"
|
||||||
|
label_settings = SubResource("LabelSettings_dx50j")
|
||||||
|
horizontal_alignment = 1
|
||||||
|
autowrap_mode = 2
|
||||||
|
max_lines_visible = 5
|
||||||
|
|
||||||
|
[node name="Timeline" type="AnimationPlayer" parent="." unique_id=512554623]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
libraries/ = SubResource("AnimationLibrary_f1hvy")
|
||||||
139
UI/Controls/chat_box.gd
Normal file
139
UI/Controls/chat_box.gd
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
@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
|
||||||
|
print("Twitcher ready!")
|
||||||
|
_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"]
|
||||||
1
UI/Controls/chat_box.gd.uid
Normal file
1
UI/Controls/chat_box.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://dcikt7pf001m8
|
||||||
26
UI/Controls/chat_box.tscn
Normal file
26
UI/Controls/chat_box.tscn
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
[gd_scene format=3 uid="uid://cstq30mjx0pch"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://dcikt7pf001m8" path="res://UI/Controls/chat_box.gd" id="1_dg5g0"]
|
||||||
|
|
||||||
|
[node name="ChatBox" type="Control" unique_id=859214320]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_dg5g0")
|
||||||
|
|
||||||
|
[node name="ChatHistory" type="ScrollContainer" parent="." unique_id=1482465110]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(0, 300)
|
||||||
|
layout_mode = 0
|
||||||
|
offset_bottom = 300.0
|
||||||
|
follow_focus = true
|
||||||
|
horizontal_scroll_mode = 0
|
||||||
|
vertical_scroll_mode = 3
|
||||||
|
|
||||||
|
[node name="History" type="VBoxContainer" parent="ChatHistory" unique_id=345296200]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
@ -11,6 +11,15 @@ func _ready() -> void:
|
||||||
%ObsPass.right = EYE_SLASH
|
%ObsPass.right = EYE_SLASH
|
||||||
%ObsPass.secret = true
|
%ObsPass.secret = true
|
||||||
%ObsPass.right_button_pressed.connect(_handle_password_show)
|
%ObsPass.right_button_pressed.connect(_handle_password_show)
|
||||||
|
%DisplayScreen.item_selected.connect(func(x): Globals.main_win.get_window().current_screen = x)
|
||||||
|
%UseScreen.pressed.connect(func():
|
||||||
|
Globals.main_win.get_window().current_screen = ProjectSettings.get_setting("display/window/size/initial_screen")
|
||||||
|
%DisplayScreen.select(Globals.main_win.get_window().current_screen)
|
||||||
|
%DisplayScreen.disabled = !%UseScreen.button_pressed
|
||||||
|
)
|
||||||
|
%AuthStreamer.pressed.connect(func(): %AuthStreamer.disabled = await Globals.twitcher.authorize_streamer())
|
||||||
|
%AuthBot.pressed.connect(func(): %AuthBot.disabled = await Globals.twitcher.authorize_chatbot())
|
||||||
|
%ConnectObs.pressed.connect(func(): ObsManager.connect_to_host())
|
||||||
_load_settings()
|
_load_settings()
|
||||||
|
|
||||||
func _load_settings() -> void:
|
func _load_settings() -> void:
|
||||||
|
|
@ -19,6 +28,42 @@ func _load_settings() -> void:
|
||||||
%ObsPass.text = Globals.settings.obs_pass
|
%ObsPass.text = Globals.settings.obs_pass
|
||||||
%AutoTwitch.button_pressed = Globals.settings.auto_connect_twitch
|
%AutoTwitch.button_pressed = Globals.settings.auto_connect_twitch
|
||||||
%AutoObs.button_pressed = Globals.settings.auto_connect_obs
|
%AutoObs.button_pressed = Globals.settings.auto_connect_obs
|
||||||
|
%ObsRecon.button_pressed = Globals.settings.obs_reconnect
|
||||||
|
|
||||||
|
%ConnectTwitch.disabled = Globals.twitcher.eventsub.is_open
|
||||||
|
%ConnectTwitch.text = "Connect Twitch" if not Globals.twitcher.eventsub.is_open else "Disconnect Twitch"
|
||||||
|
|
||||||
|
for scr in DisplayServer.get_screen_count():
|
||||||
|
%DisplayScreen.add_item("Monitor %d" % (scr + 1))
|
||||||
|
if Globals.settings.display_screen == -1:
|
||||||
|
%UseScreen.button_pressed = false
|
||||||
|
%DisplayScreen.disabled = true
|
||||||
|
else:
|
||||||
|
%UseScreen.button_pressed = true
|
||||||
|
%DisplayScreen.select(Globals.settings.display_screen)
|
||||||
|
%DisplayScreen.disabled = false
|
||||||
|
|
||||||
|
if not Globals.twitcher.streamer_token_loaded:
|
||||||
|
var res := await Globals.twitcher.load_streamer_token()
|
||||||
|
if res == TwitcherExtended.AuthStatus.UNAUTHORIZED:
|
||||||
|
%AuthStreamer.disabled = false
|
||||||
|
else:
|
||||||
|
%AuthStreamer.disabled = true
|
||||||
|
%StreamerName.text = Globals.twitcher.streamer_user.display_name
|
||||||
|
else:
|
||||||
|
%AuthStreamer.disabled = true
|
||||||
|
%StreamerName.text = Globals.twitcher.streamer_user.display_name
|
||||||
|
|
||||||
|
if not Globals.twitcher.chatbot_token_loaded:
|
||||||
|
var res := await Globals.twitcher.load_chatbot_token()
|
||||||
|
if res == TwitcherExtended.AuthStatus.UNAUTHORIZED:
|
||||||
|
%AuthBot.disabled = false
|
||||||
|
else:
|
||||||
|
%AuthBot.disabled = true
|
||||||
|
%BotName.text = Globals.twitcher.bot_user.display_name
|
||||||
|
else:
|
||||||
|
%AuthBot.disabled = true
|
||||||
|
%BotName.text = Globals.twitcher.bot_user.display_name
|
||||||
|
|
||||||
func apply_settings() -> void:
|
func apply_settings() -> void:
|
||||||
Globals.settings.obs_host = %ObsHost.text
|
Globals.settings.obs_host = %ObsHost.text
|
||||||
|
|
@ -26,6 +71,12 @@ func apply_settings() -> void:
|
||||||
Globals.settings.obs_pass = %ObsPass.text
|
Globals.settings.obs_pass = %ObsPass.text
|
||||||
Globals.settings.auto_connect_twitch = %AutoTwitch.button_pressed
|
Globals.settings.auto_connect_twitch = %AutoTwitch.button_pressed
|
||||||
Globals.settings.auto_connect_obs = %AutoObs.button_pressed
|
Globals.settings.auto_connect_obs = %AutoObs.button_pressed
|
||||||
|
Globals.settings.obs_reconnect = %ObsRecon.button_pressed
|
||||||
|
if %UseScreen.button_pressed:
|
||||||
|
Globals.settings.display_screen = %DisplayScreen.selected
|
||||||
|
else:
|
||||||
|
Globals.settings.display_screen = -1
|
||||||
|
Globals.main_win.get_window().current_screen = ProjectSettings.get_setting("display/window/size/initial_screen")
|
||||||
|
|
||||||
func _handle_password_show() -> void:
|
func _handle_password_show() -> void:
|
||||||
if %ObsPass.right == EYE_SLASH:
|
if %ObsPass.right == EYE_SLASH:
|
||||||
|
|
@ -34,3 +85,6 @@ func _handle_password_show() -> void:
|
||||||
else:
|
else:
|
||||||
%ObsPass.right = EYE_SLASH
|
%ObsPass.right = EYE_SLASH
|
||||||
%ObsPass.secret = true
|
%ObsPass.secret = true
|
||||||
|
|
||||||
|
func _exit_tree() -> void:
|
||||||
|
apply_settings()
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_7naex"]
|
[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_7naex"]
|
||||||
content_margin_left = 10.0
|
content_margin_left = 10.0
|
||||||
content_margin_top = 8.0
|
content_margin_top = 8.0
|
||||||
content_margin_right = 78.538
|
content_margin_right = 181.345
|
||||||
texture = ExtResource("2_7naex")
|
texture = ExtResource("2_7naex")
|
||||||
texture_margin_left = 3.08429
|
texture_margin_left = 3.08429
|
||||||
texture_margin_top = 5.50548
|
texture_margin_top = 5.50548
|
||||||
|
|
@ -19,7 +19,7 @@ region_rect = Rect2(93, 474, 41, 33)
|
||||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_en626"]
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_en626"]
|
||||||
content_margin_left = 4.0
|
content_margin_left = 4.0
|
||||||
content_margin_top = 4.0
|
content_margin_top = 4.0
|
||||||
content_margin_right = 72.538
|
content_margin_right = 175.345
|
||||||
content_margin_bottom = 4.0
|
content_margin_bottom = 4.0
|
||||||
bg_color = Color(0.1, 0.1, 0.1, 0.3)
|
bg_color = Color(0.1, 0.1, 0.1, 0.3)
|
||||||
border_width_bottom = 2
|
border_width_bottom = 2
|
||||||
|
|
@ -33,7 +33,7 @@ corner_detail = 5
|
||||||
[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_v8ga3"]
|
[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_v8ga3"]
|
||||||
content_margin_left = 10.0
|
content_margin_left = 10.0
|
||||||
content_margin_top = 8.0
|
content_margin_top = 8.0
|
||||||
content_margin_right = 78.538
|
content_margin_right = 181.345
|
||||||
texture = ExtResource("2_7naex")
|
texture = ExtResource("2_7naex")
|
||||||
texture_margin_left = 3.08429
|
texture_margin_left = 3.08429
|
||||||
texture_margin_top = 5.50548
|
texture_margin_top = 5.50548
|
||||||
|
|
@ -218,3 +218,26 @@ unique_name_in_owner = true
|
||||||
custom_minimum_size = Vector2(240, 0)
|
custom_minimum_size = Vector2(240, 0)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "Connect OBS"
|
text = "Connect OBS"
|
||||||
|
|
||||||
|
[node name="Control3" type="Control" parent="MarginContainer/VBoxContainer" unique_id=292441254]
|
||||||
|
custom_minimum_size = Vector2(0, 20)
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Label4" type="Label" parent="MarginContainer/VBoxContainer" unique_id=1102442861]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Display"
|
||||||
|
|
||||||
|
[node name="HSeparator4" type="HSeparator" parent="MarginContainer/VBoxContainer" unique_id=2077615507]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer" unique_id=1279240869]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="UseScreen" type="CheckBox" parent="MarginContainer/VBoxContainer/HBoxContainer" unique_id=480029198]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Use Specific Screen:"
|
||||||
|
|
||||||
|
[node name="DisplayScreen" type="OptionButton" parent="MarginContainer/VBoxContainer/HBoxContainer" unique_id=151546822]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ func _ready() -> void:
|
||||||
|
|
||||||
func _handle_run_script() -> void:
|
func _handle_run_script() -> void:
|
||||||
var script = GDScript.new()
|
var script = GDScript.new()
|
||||||
script.source_code = %CodeEditor.text
|
script.source_code = %CodeEditor.text.replace("\t"," ")
|
||||||
var error := script.reload()
|
var error := script.reload()
|
||||||
if error != OK:
|
if error != OK:
|
||||||
print("Failed to parse script!")
|
print("Failed to parse script!")
|
||||||
|
|
|
||||||
BIN
UI/assets/fonts/Yellowtail.woff2
Normal file
BIN
UI/assets/fonts/Yellowtail.woff2
Normal file
Binary file not shown.
36
UI/assets/fonts/Yellowtail.woff2.import
Normal file
36
UI/assets/fonts/Yellowtail.woff2.import
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="font_data_dynamic"
|
||||||
|
type="FontFile"
|
||||||
|
uid="uid://o4e6chcu01yx"
|
||||||
|
path="res://.godot/imported/Yellowtail.woff2-87764a42e0e85c9b21b77a80b21ffabf.fontdata"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://UI/assets/fonts/Yellowtail.woff2"
|
||||||
|
dest_files=["res://.godot/imported/Yellowtail.woff2-87764a42e0e85c9b21b77a80b21ffabf.fontdata"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
Rendering=null
|
||||||
|
antialiasing=1
|
||||||
|
generate_mipmaps=false
|
||||||
|
disable_embedded_bitmaps=true
|
||||||
|
multichannel_signed_distance_field=false
|
||||||
|
msdf_pixel_range=8
|
||||||
|
msdf_size=48
|
||||||
|
allow_system_fallback=true
|
||||||
|
force_autohinter=false
|
||||||
|
modulate_color_glyphs=false
|
||||||
|
hinting=1
|
||||||
|
subpixel_positioning=4
|
||||||
|
keep_rounding_remainders=true
|
||||||
|
oversampling=0.0
|
||||||
|
Fallbacks=null
|
||||||
|
fallbacks=[]
|
||||||
|
Compress=null
|
||||||
|
compress=true
|
||||||
|
preload=[]
|
||||||
|
language_support={}
|
||||||
|
script_support={}
|
||||||
|
opentype_features={}
|
||||||
BIN
UI/assets/fonts/rage.woff2
Normal file
BIN
UI/assets/fonts/rage.woff2
Normal file
Binary file not shown.
36
UI/assets/fonts/rage.woff2.import
Normal file
36
UI/assets/fonts/rage.woff2.import
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="font_data_dynamic"
|
||||||
|
type="FontFile"
|
||||||
|
uid="uid://c30qqiv6sqheh"
|
||||||
|
path="res://.godot/imported/rage.woff2-9e1ac0979775e72c3e1a8a37972e5b0d.fontdata"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://UI/assets/fonts/rage.woff2"
|
||||||
|
dest_files=["res://.godot/imported/rage.woff2-9e1ac0979775e72c3e1a8a37972e5b0d.fontdata"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
Rendering=null
|
||||||
|
antialiasing=1
|
||||||
|
generate_mipmaps=false
|
||||||
|
disable_embedded_bitmaps=true
|
||||||
|
multichannel_signed_distance_field=false
|
||||||
|
msdf_pixel_range=8
|
||||||
|
msdf_size=48
|
||||||
|
allow_system_fallback=true
|
||||||
|
force_autohinter=false
|
||||||
|
modulate_color_glyphs=false
|
||||||
|
hinting=1
|
||||||
|
subpixel_positioning=4
|
||||||
|
keep_rounding_remainders=true
|
||||||
|
oversampling=0.0
|
||||||
|
Fallbacks=null
|
||||||
|
fallbacks=[]
|
||||||
|
Compress=null
|
||||||
|
compress=true
|
||||||
|
preload=[]
|
||||||
|
language_support={}
|
||||||
|
script_support={}
|
||||||
|
opentype_features={}
|
||||||
BIN
UI/assets/video/Backgrounds/Bits-Synthwave.webm
Normal file
BIN
UI/assets/video/Backgrounds/Bits-Synthwave.webm
Normal file
Binary file not shown.
BIN
UI/assets/video/Backgrounds/Grid-Synthwave.webm
Normal file
BIN
UI/assets/video/Backgrounds/Grid-Synthwave.webm
Normal file
Binary file not shown.
BIN
UI/assets/video/Backgrounds/Lightning-Synthwave.webm
Normal file
BIN
UI/assets/video/Backgrounds/Lightning-Synthwave.webm
Normal file
Binary file not shown.
BIN
UI/assets/video/Backgrounds/Sphere-Synthwave.webm
Normal file
BIN
UI/assets/video/Backgrounds/Sphere-Synthwave.webm
Normal file
Binary file not shown.
BIN
UI/assets/video/Backgrounds/Stripes-Synthwave.webm
Normal file
BIN
UI/assets/video/Backgrounds/Stripes-Synthwave.webm
Normal file
Binary file not shown.
BIN
UI/assets/video/Backgrounds/Sunrise-Synthwave.webm
Normal file
BIN
UI/assets/video/Backgrounds/Sunrise-Synthwave.webm
Normal file
Binary file not shown.
BIN
UI/assets/video/Backgrounds/Triangle-Synthwave.webm
Normal file
BIN
UI/assets/video/Backgrounds/Triangle-Synthwave.webm
Normal file
Binary file not shown.
BIN
UI/assets/video/Icons/Car-Synthwave.webm
Normal file
BIN
UI/assets/video/Icons/Car-Synthwave.webm
Normal file
Binary file not shown.
BIN
UI/assets/video/Icons/Cassette-Synthwave.webm
Normal file
BIN
UI/assets/video/Icons/Cassette-Synthwave.webm
Normal file
Binary file not shown.
BIN
UI/assets/video/Icons/Computer-Synthwave.webm
Normal file
BIN
UI/assets/video/Icons/Computer-Synthwave.webm
Normal file
Binary file not shown.
BIN
UI/assets/video/Icons/Hoverboard-Synthwave.webm
Normal file
BIN
UI/assets/video/Icons/Hoverboard-Synthwave.webm
Normal file
Binary file not shown.
BIN
UI/assets/video/Icons/Joystick-Synthwave.webm
Normal file
BIN
UI/assets/video/Icons/Joystick-Synthwave.webm
Normal file
Binary file not shown.
BIN
UI/assets/video/Icons/Phone-Synthwave.webm
Normal file
BIN
UI/assets/video/Icons/Phone-Synthwave.webm
Normal file
Binary file not shown.
BIN
UI/assets/video/Icons/Stars-Synthwave.webm
Normal file
BIN
UI/assets/video/Icons/Stars-Synthwave.webm
Normal file
Binary file not shown.
|
|
@ -7,6 +7,53 @@ const COL_OFF := Color.LIGHT_SALMON
|
||||||
const SETTINGS_PANEL = preload("res://UI/settings_panel.tscn")
|
const SETTINGS_PANEL = preload("res://UI/settings_panel.tscn")
|
||||||
const SCRIPT_EDITOR = preload("res://UI/Controls/script_editor.tscn")
|
const SCRIPT_EDITOR = preload("res://UI/Controls/script_editor.tscn")
|
||||||
|
|
||||||
|
#region Alerts (Testing)
|
||||||
|
const FOLLOW_ALERT = preload("res://UI/Alerts/follow_alert.tscn")
|
||||||
|
const CHEER_ALERT = preload("res://UI/Alerts/cheer_alert.tscn")
|
||||||
|
const RAID_ALERT = preload("res://UI/Alerts/raid_alert.tscn")
|
||||||
|
const SUBSCRIBER_ALERT = preload("res://UI/Alerts/subscriber_alert.tscn")
|
||||||
|
var _impl_alerts: Array = [
|
||||||
|
FOLLOW_ALERT,
|
||||||
|
CHEER_ALERT,
|
||||||
|
RAID_ALERT,
|
||||||
|
SUBSCRIBER_ALERT,
|
||||||
|
]
|
||||||
|
|
||||||
|
const RANDOM_NAMES := [
|
||||||
|
"Voylin",
|
||||||
|
"meneldal",
|
||||||
|
"Pengo",
|
||||||
|
"Adam",
|
||||||
|
"Yagich",
|
||||||
|
"Falinere",
|
||||||
|
"Eroaxee",
|
||||||
|
"wolbee",
|
||||||
|
"JeSuisEmma",
|
||||||
|
"Temptic404",
|
||||||
|
"RobitussinMD",
|
||||||
|
"spimort",
|
||||||
|
"FuzzyDemonBunny",
|
||||||
|
"OdatNurd",
|
||||||
|
]
|
||||||
|
|
||||||
|
const RANDOM_MESSAGES := [
|
||||||
|
"Android was an easy fix, accidentally applied vpx to everything in Scons, Windows need an AUR package, and the arm builds are complaining about not finding vpx (probably no static build available). So not too difficult to fix luckily. But for arm I might need to build vpx myself for those builds, and whilst I'm at it I can implement support for Android as I need to clone and build it anyway for the arm builds ... Well ... that will be for later as I'll probably get stuck on this for the entire day without finishing what I started working on before XD",
|
||||||
|
"awesome, im going to run the project update tool with 4.6 and PR that so that we don't have 4.6 upgraded files in future PRs",
|
||||||
|
"I can do any time during the day or night, I can even wake up in the middle of the night if I need to",
|
||||||
|
"done 🙂 ready when you are",
|
||||||
|
"you probably been busy lately, but just curious how progress was coming along on the new launcher?",
|
||||||
|
"A version or two ago they moved the strip properties from the sequencer timeline (in blue) to the generic \"properties\" panel (in red) thats used everywhere else.",
|
||||||
|
"thanks, I realised my models were all subdivided triangle riddled messes!",
|
||||||
|
"I still don't know how to make a good short - but I can't get over the background music I was able to generate for this one. It just cracks me up. ",
|
||||||
|
"i think my favourite thing about streaming game dev is just how much of us are just sitting there guessing???",
|
||||||
|
"148 TEAM MEMBERS AND NOBODY TO WATCH ON A SUNDAY EVENING flips table",
|
||||||
|
"i'd like to formally apologize to @iRad for how i treated him in my really weird dream last night. we entered a game jam together and i spent the entire time talking to friends. he really carried me.",
|
||||||
|
"Sometimes that’s all it takes, just one person believing you’ll succeed. Or sometimes a whole bunch of people, who mysteriously growl low if you try and leave the chair. And in no way shape or form require you to send eye blinking messages for outside help, nor throw digital snacks in one direction while sneaking out the other. ",
|
||||||
|
"That's the reason I come into the communities, to be supportive, positive, try to help when possible... because game dev is already hard enough. Sometimes all you need is just that one little boost on a rough day to keep you going and just offset the grind enough to let you feel okay again. That and giving friendly pushes to devs to get that steam page done, or that demo knocked out, or just to push forward progress.",
|
||||||
|
"Born to late to explore Earth, born to early to explore the universe",
|
||||||
|
]
|
||||||
|
#endregion
|
||||||
|
|
||||||
# Indicators
|
# Indicators
|
||||||
@onready var indicators: Control = %indicators
|
@onready var indicators: Control = %indicators
|
||||||
@onready var ind_stream: TextureRect = %ind_stream
|
@onready var ind_stream: TextureRect = %ind_stream
|
||||||
|
|
@ -18,6 +65,7 @@ const SCRIPT_EDITOR = preload("res://UI/Controls/script_editor.tscn")
|
||||||
@onready var btn_run_obs: GDSubMenuButton = %btn_run_obs
|
@onready var btn_run_obs: GDSubMenuButton = %btn_run_obs
|
||||||
@onready var btn_step_away: GDSubMenuButton = %btn_step_away
|
@onready var btn_step_away: GDSubMenuButton = %btn_step_away
|
||||||
@onready var btn_tuber: GDSubMenuButton = %btn_tuber
|
@onready var btn_tuber: GDSubMenuButton = %btn_tuber
|
||||||
|
@onready var btn_camera: GDSubMenuButton = %btn_camera
|
||||||
@onready var btn_chat: GDSubMenuButton = %btn_chat
|
@onready var btn_chat: GDSubMenuButton = %btn_chat
|
||||||
@onready var btn_script_editor: GDSubMenuButton = %btn_script_editor
|
@onready var btn_script_editor: GDSubMenuButton = %btn_script_editor
|
||||||
@onready var btn_user_list: GDSubMenuButton = %btn_user_list
|
@onready var btn_user_list: GDSubMenuButton = %btn_user_list
|
||||||
|
|
@ -29,6 +77,17 @@ var anchored_position: Vector2
|
||||||
|
|
||||||
var _set_win: Window
|
var _set_win: Window
|
||||||
var _edit_win: Window
|
var _edit_win: Window
|
||||||
|
var _obs_pid: int = -1
|
||||||
|
var _vtuber_pid: int = -1
|
||||||
|
var _vtuber_sid: int
|
||||||
|
var _camera_sid: int
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
ObsManager.obs_ready.connect(_handle_obs_connect)
|
||||||
|
|
||||||
|
func _handle_obs_connect() -> void:
|
||||||
|
_vtuber_sid = await ObsManager.get_scene_item_id("~Avatar", "~VTuber")
|
||||||
|
_camera_sid = await ObsManager.get_scene_item_id("~Avatar", "~WebCam")
|
||||||
|
|
||||||
func start(_main_menu_button: GDSubMenuButton = null) -> void:
|
func start(_main_menu_button: GDSubMenuButton = null) -> void:
|
||||||
anchored_position = position
|
anchored_position = position
|
||||||
|
|
@ -40,8 +99,6 @@ func start(_main_menu_button: GDSubMenuButton = null) -> void:
|
||||||
_connect_signals()
|
_connect_signals()
|
||||||
|
|
||||||
func start_indicators() -> void:
|
func start_indicators() -> void:
|
||||||
# TODO: Setup NO-OBS-WS Stuff
|
|
||||||
|
|
||||||
var tot = indicators.get_child_count()
|
var tot = indicators.get_child_count()
|
||||||
for i in tot:
|
for i in tot:
|
||||||
var ind: TextureRect = indicators.get_child(i)
|
var ind: TextureRect = indicators.get_child(i)
|
||||||
|
|
@ -49,8 +106,6 @@ func start_indicators() -> void:
|
||||||
ind.position = (size/2 - ind.size/2)
|
ind.position = (size/2 - ind.size/2)
|
||||||
ind.position += Vector2.from_angle(TAU*i/tot + PI/2) * (size.x/2 - ind.size.x/2)
|
ind.position += Vector2.from_angle(TAU*i/tot + PI/2) * (size.x/2 - ind.size.x/2)
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
func generate_panels_buttons() -> void:
|
func generate_panels_buttons() -> void:
|
||||||
# TODO: Generate Panels?
|
# TODO: Generate Panels?
|
||||||
pass
|
pass
|
||||||
|
|
@ -105,6 +160,9 @@ func _connect_signals() -> void:
|
||||||
btn_settings.properly_pressed.connect(_handle_settings)
|
btn_settings.properly_pressed.connect(_handle_settings)
|
||||||
btn_script_editor.properly_pressed.connect(_handle_script_editor)
|
btn_script_editor.properly_pressed.connect(_handle_script_editor)
|
||||||
btn_run_obs.properly_pressed.connect(_handle_run_obs)
|
btn_run_obs.properly_pressed.connect(_handle_run_obs)
|
||||||
|
btn_step_away.properly_pressed.connect(_handle_step_away)
|
||||||
|
btn_tuber.properly_pressed.connect(_handle_run_vtuber)
|
||||||
|
btn_camera.properly_pressed.connect(_handle_camera)
|
||||||
|
|
||||||
|
|
||||||
func _handle_settings() -> void:
|
func _handle_settings() -> void:
|
||||||
|
|
@ -141,5 +199,53 @@ func _handle_script_editor() -> void:
|
||||||
_edit_win = win
|
_edit_win = win
|
||||||
|
|
||||||
func _handle_run_obs() -> void:
|
func _handle_run_obs() -> void:
|
||||||
EventManager.test_notification("Hello World!")
|
var tree := ProcessTree.new()
|
||||||
|
if tree.has_process_name(Globals.settings.obs_name):
|
||||||
|
print("OBS is running.")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
OS.create_process(Globals.settings.obs_path, [])
|
||||||
|
|
||||||
|
|
||||||
|
func _handle_step_away() -> void:
|
||||||
|
var alert = _impl_alerts.pick_random().instantiate()
|
||||||
|
if alert is FollowAlert:
|
||||||
|
alert.setup(RANDOM_NAMES.pick_random())
|
||||||
|
elif alert is CheerAlert:
|
||||||
|
alert.setup(RANDOM_NAMES.pick_random(), randi_range(10,1000), RANDOM_MESSAGES.pick_random())
|
||||||
|
elif alert is RaidAlert:
|
||||||
|
alert.setup(RANDOM_NAMES.pick_random(), randi_range(5,500))
|
||||||
|
elif alert is SubscriberAlert:
|
||||||
|
var prime: bool = randf() < 0.25
|
||||||
|
var months: int = randi_range(0,64) if randf() < 0.25 else 1
|
||||||
|
var tier: bool = randi_range(1,3)
|
||||||
|
var msg: String = RANDOM_MESSAGES.pick_random() if randf() < 0.45 else ""
|
||||||
|
alert.setup(RANDOM_NAMES.pick_random(), months, prime, tier, msg)
|
||||||
|
EventManager.add_alert(alert)
|
||||||
|
|
||||||
|
func _handle_run_vtuber() -> void:
|
||||||
|
var tree := ProcessTree.new()
|
||||||
|
if tree.has_process_name(Globals.settings.vtuber_name):
|
||||||
|
print("VTuber is running.")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
OS.create_process(Globals.settings.vtuber_path, [Globals.settings.vtuber_model_path])
|
||||||
|
|
||||||
|
func _handle_camera() -> void:
|
||||||
|
if not ObsManager.is_open(): return
|
||||||
|
var vtuber_vis := await ObsManager.get_item_enabled("~Avatar", _vtuber_sid)
|
||||||
|
ObsManager.set_item_enabled("~Avatar",_vtuber_sid, !vtuber_vis)
|
||||||
|
ObsManager.set_item_enabled("~Avatar",_camera_sid, vtuber_vis)
|
||||||
|
var aid := await ObsManager.get_scene_item_id("Talking", "~Avatar")
|
||||||
|
var transform := await ObsManager.get_item_transform("Talking", aid)
|
||||||
|
transform.bounds_width = 1.0
|
||||||
|
transform.bounds_height = 1.0
|
||||||
|
if vtuber_vis:
|
||||||
|
transform.position_x = 70
|
||||||
|
transform.position_y = 320
|
||||||
|
else:
|
||||||
|
transform.position_x = 39
|
||||||
|
transform.position_y = 492
|
||||||
|
print("Moving ~Avatar to: %s" % [{"x": transform.position_x, "y": transform.position_y}])
|
||||||
|
ObsManager.set_item_transform("Talking", aid, transform)
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
||||||
|
|
@ -180,8 +180,8 @@ metadata/_custom_type_script = "uid://8715vyt7prmd"
|
||||||
[node name="btn_tuber" type="Button" parent="btn_obs" unique_id=118706136]
|
[node name="btn_tuber" type="Button" parent="btn_obs" unique_id=118706136]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_right = 40.0
|
offset_right = 66.0
|
||||||
offset_bottom = 40.0
|
offset_bottom = 66.0
|
||||||
tooltip_text = "Launch VTuber"
|
tooltip_text = "Launch VTuber"
|
||||||
icon = ExtResource("12_05x4r")
|
icon = ExtResource("12_05x4r")
|
||||||
script = ExtResource("8_ttodq")
|
script = ExtResource("8_ttodq")
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,12 @@ visible = false
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
metadata/_tab_index = 1
|
metadata/_tab_index = 1
|
||||||
|
|
||||||
[node name="Chat Avatars" type="PanelContainer" parent="MarginContainer/VBoxContainer/TabContainer" unique_id=429108220]
|
[node name="Music" type="PanelContainer" parent="MarginContainer/VBoxContainer/TabContainer" unique_id=22912491]
|
||||||
visible = false
|
visible = false
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
metadata/_tab_index = 2
|
metadata/_tab_index = 2
|
||||||
|
|
||||||
|
[node name="Chat Avatars" type="PanelContainer" parent="MarginContainer/VBoxContainer/TabContainer" unique_id=429108220]
|
||||||
|
visible = false
|
||||||
|
layout_mode = 2
|
||||||
|
metadata/_tab_index = 3
|
||||||
|
|
|
||||||
7
addons/custom_runner/plugin.cfg
Normal file
7
addons/custom_runner/plugin.cfg
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
[plugin]
|
||||||
|
|
||||||
|
name="Custom Runner"
|
||||||
|
description="A plugin that runs the Godot Engine with a specific tool, such as obs-gamecapture, to capture the game window."
|
||||||
|
author="Mario Steele"
|
||||||
|
version="0.1"
|
||||||
|
script="plugin.gd"
|
||||||
151
addons/custom_runner/plugin.gd
Normal file
151
addons/custom_runner/plugin.gd
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
@tool
|
||||||
|
extends EditorPlugin
|
||||||
|
|
||||||
|
var _runner_btn: RunnerButton
|
||||||
|
var _play_icon: Texture2D
|
||||||
|
var _stop_icon: Texture2D
|
||||||
|
|
||||||
|
func _enter_tree() -> void:
|
||||||
|
ProjectSettings.set("application/run/custom_runner", "")
|
||||||
|
ProjectSettings.add_property_info({
|
||||||
|
"name": "application/run/custom_runner",
|
||||||
|
"type": TYPE_STRING,
|
||||||
|
"hint": PROPERTY_HINT_GLOBAL_FILE,
|
||||||
|
"hint_string": ""
|
||||||
|
})
|
||||||
|
_runner_btn = RunnerButton.new()
|
||||||
|
add_control_to_container(EditorPlugin.CONTAINER_TOOLBAR, _runner_btn)
|
||||||
|
|
||||||
|
var cnt := _runner_btn.get_parent()
|
||||||
|
cnt.move_child(_runner_btn, cnt.get_child_count() - 3)
|
||||||
|
|
||||||
|
|
||||||
|
func _exit_tree() -> void:
|
||||||
|
remove_control_from_container(EditorPlugin.CONTAINER_TOOLBAR, _runner_btn)
|
||||||
|
_runner_btn.queue_free()
|
||||||
|
_runner_btn = null
|
||||||
|
|
||||||
|
|
||||||
|
class RunnerButton:
|
||||||
|
extends Button
|
||||||
|
|
||||||
|
var _play: Texture2D
|
||||||
|
var _stop: Texture2D
|
||||||
|
var _running_pid: int = -1
|
||||||
|
var _io: FileAccess = null
|
||||||
|
var _err: FileAccess = null
|
||||||
|
|
||||||
|
func _init() -> void:
|
||||||
|
_play = EditorInterface.get_editor_theme().get_icon(&"Play", &"EditorIcons")
|
||||||
|
_stop = EditorInterface.get_editor_theme().get_icon(&"Stop", &"EditorIcons")
|
||||||
|
shortcut = Shortcut.new()
|
||||||
|
var key := InputEventKey.new()
|
||||||
|
key.keycode = KEY_F5
|
||||||
|
key.shift_pressed = true
|
||||||
|
shortcut.events = [key]
|
||||||
|
modulate = Color.GREEN
|
||||||
|
var esb := StyleBoxEmpty.new()
|
||||||
|
add_theme_stylebox_override(&"normal", esb)
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
icon = _play
|
||||||
|
|
||||||
|
func _process(_d: float) -> void:
|
||||||
|
if _running_pid == -1: return
|
||||||
|
if not OS.is_process_running(_running_pid):
|
||||||
|
_running_pid = -1
|
||||||
|
icon = _play
|
||||||
|
modulate = Color.GREEN
|
||||||
|
|
||||||
|
func _pressed() -> void:
|
||||||
|
if _running_pid != -1:
|
||||||
|
OS.kill(_running_pid)
|
||||||
|
_running_pid = -1
|
||||||
|
icon = _play
|
||||||
|
modulate = Color.GREEN
|
||||||
|
return
|
||||||
|
|
||||||
|
var runner := ProjectSettings.get_setting("application/run/custom_runner", "")
|
||||||
|
if runner == "":
|
||||||
|
EditorInterface.play_main_scene()
|
||||||
|
return
|
||||||
|
|
||||||
|
if not FileAccess.file_exists(runner):
|
||||||
|
EditorInterface.get_editor_toaster().push_toast("Custom runner does not exist!",
|
||||||
|
EditorToaster.SEVERITY_ERROR,
|
||||||
|
"Provide the full path to the custom runner!")
|
||||||
|
return
|
||||||
|
|
||||||
|
var godot = OS.get_executable_path()
|
||||||
|
var project = ProjectSettings.globalize_path("res://").rstrip("/")
|
||||||
|
var host: String = EditorInterface.get_editor_settings().get_setting("network/debug/remote_host")
|
||||||
|
var port: int = EditorInterface.get_editor_settings().get_setting("network/debug/remote_port")
|
||||||
|
var pid: int = OS.get_process_id()
|
||||||
|
var main_scene: String = ProjectSettings.get_setting("application/run/main_scene")
|
||||||
|
var run_arguments := [
|
||||||
|
godot,
|
||||||
|
"--path", project,
|
||||||
|
"-d"
|
||||||
|
#"--remote-debug", "tcp://%s:%s" % [host, port],
|
||||||
|
#"--editor-pid", "%s" % pid,
|
||||||
|
#"--position", "320,-24",
|
||||||
|
#"--scene", main_scene
|
||||||
|
]
|
||||||
|
# --remote-debug tcp://127.0.0.1:6007 --editor-pid 3480813 --position 320,-24 --scene uid://2t2hslaaewee
|
||||||
|
print("Executing project with the following Command Line: %s %s" % [runner, run_arguments])
|
||||||
|
|
||||||
|
|
||||||
|
#_running_pid = OS.create_process(runner, run_arguments)
|
||||||
|
var res := OS.execute_with_pipe(runner, run_arguments, false)
|
||||||
|
|
||||||
|
if res.is_empty():
|
||||||
|
EditorInterface.get_editor_toaster().push_toast("Failed to Run custom runner.",EditorToaster.SEVERITY_ERROR)
|
||||||
|
|
||||||
|
_running_pid = res.pid
|
||||||
|
_io = res.stdio
|
||||||
|
_err = res.stderr
|
||||||
|
|
||||||
|
icon = _stop
|
||||||
|
modulate = Color.RED
|
||||||
|
_monitor_input_output()
|
||||||
|
|
||||||
|
func _monitor_input_output() -> void:
|
||||||
|
var output: PackedByteArray = []
|
||||||
|
var err: PackedByteArray = []
|
||||||
|
|
||||||
|
while OS.is_process_running(_running_pid):
|
||||||
|
await get_tree().process_frame
|
||||||
|
|
||||||
|
var res := _read_io(_io, output)
|
||||||
|
if res != "":
|
||||||
|
print_rich(res)
|
||||||
|
|
||||||
|
res = _read_io(_err, err)
|
||||||
|
if res != "":
|
||||||
|
print_rich(res)
|
||||||
|
|
||||||
|
await get_tree().process_frame
|
||||||
|
var str := _read_io(_io, output)
|
||||||
|
if str != "":
|
||||||
|
print(str)
|
||||||
|
|
||||||
|
str = _read_io(_err, err)
|
||||||
|
if str != "":
|
||||||
|
print(str)
|
||||||
|
_io.close()
|
||||||
|
_err.close()
|
||||||
|
_io = null
|
||||||
|
_err = null
|
||||||
|
|
||||||
|
func _read_io(io: FileAccess, buffer: PackedByteArray) -> String:
|
||||||
|
if io.get_position() < io.get_length():
|
||||||
|
buffer.append_array(io.get_buffer(io.get_length() - io.get_position()))
|
||||||
|
var nl = buffer.rfind(10)
|
||||||
|
if nl == -1:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
var part := buffer.slice(0,nl)
|
||||||
|
var leftover := buffer.slice(nl+1)
|
||||||
|
buffer.clear()
|
||||||
|
buffer.append_array(leftover)
|
||||||
|
return part.get_string_from_utf8()
|
||||||
1
addons/custom_runner/plugin.gd.uid
Normal file
1
addons/custom_runner/plugin.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://bsdgmd1nimt6n
|
||||||
|
|
@ -9,6 +9,9 @@ To see video files in your projects file tree, you need to add `mp4` and any oth
|
||||||
1. When exporting, you'll have your executable and the GDE GoZen library file, these do need to be both shared for the application to work.
|
1. When exporting, you'll have your executable and the GDE GoZen library file, these do need to be both shared for the application to work.
|
||||||
2. Also, you will have to add `*.mp4` and other extension names of your video files to the resources which need to get exported for each platform you want to export for, otherwise your video files will not be included in your final export.
|
2. Also, you will have to add `*.mp4` and other extension names of your video files to the resources which need to get exported for each platform you want to export for, otherwise your video files will not be included in your final export.
|
||||||
|
|
||||||
|
## Android (SAF)
|
||||||
|
Due to the way SAF works (Godot 4.6+), accessing files through the browser might give invalid paths. You need to be certain you get the absolute path instead. Inside of the `test_room` you can find an example of how this is done for Android, by basically copying the videos to a temporary folder which will give an absolute path. Only thing to be careful of is to also remove the data afterwards out of the temporary folder.
|
||||||
|
|
||||||
## Help needed?
|
## Help needed?
|
||||||
You can go to the [GitHub repo](https://github.com/VoylinsGamedevJourney/gde_gozen/issues) to report problems, or visit out [Discord server](discord.gg/BdbUf7VKYC) for help/advice.
|
You can go to the [GitHub repo](https://github.com/VoylinsGamedevJourney/gde_gozen/issues) to report problems, or visit out [Discord server](discord.gg/BdbUf7VKYC) for help/advice.
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://bijjjb1qmqf7f"
|
uid="uid://dcpha8teexb00"
|
||||||
path="res://.godot/imported/icon.svg-ac53c9c419a88eda808214a4d44243c3.ctex"
|
path="res://.godot/imported/icon.svg-ac53c9c419a88eda808214a4d44243c3.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"vram_texture": false
|
"vram_texture": false
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://dbk4jierdjfrf"
|
uid="uid://bndqydg778xif"
|
||||||
path="res://.godot/imported/icon.webp-a5a23a9a73b8ba8140cf260e6bfffac7.ctex"
|
path="res://.godot/imported/icon.webp-a5a23a9a73b8ba8140cf260e6bfffac7.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"vram_texture": false
|
"vram_texture": false
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,5 @@
|
||||||
name="gde_gozen"
|
name="gde_gozen"
|
||||||
description="Providing performant video playback."
|
description="Providing performant video playback."
|
||||||
author="Voylin's Gamedev Journey"
|
author="Voylin's Gamedev Journey"
|
||||||
version="v9.1"
|
version="v9.2"
|
||||||
script="plugin.gd"
|
script="plugin.gd"
|
||||||
|
|
|
||||||
|
|
@ -107,11 +107,9 @@ func _exit_tree() -> void:
|
||||||
# Making certain no remaining tasks are running in separate threads.
|
# Making certain no remaining tasks are running in separate threads.
|
||||||
if _video_thread != -1:
|
if _video_thread != -1:
|
||||||
var error: int = WorkerThreadPool.wait_for_task_completion(_video_thread)
|
var error: int = WorkerThreadPool.wait_for_task_completion(_video_thread)
|
||||||
|
|
||||||
if error != OK:
|
if error != OK:
|
||||||
printerr("Something went wrong waiting for task completion! %s" % error)
|
printerr("Something went wrong waiting for task completion! %s" % error)
|
||||||
_video_thread = -1
|
_video_thread = -1
|
||||||
|
|
||||||
if video != null:
|
if video != null:
|
||||||
close()
|
close()
|
||||||
|
|
||||||
|
|
@ -129,7 +127,6 @@ func _ready() -> void:
|
||||||
func set_video_path(new_path: String) -> void:
|
func set_video_path(new_path: String) -> void:
|
||||||
if video != null:
|
if video != null:
|
||||||
close()
|
close()
|
||||||
|
|
||||||
if !is_node_ready():
|
if !is_node_ready():
|
||||||
await ready
|
await ready
|
||||||
if !get_tree().root.is_node_ready():
|
if !get_tree().root.is_node_ready():
|
||||||
|
|
@ -144,25 +141,26 @@ func set_video_path(new_path: String) -> void:
|
||||||
|
|
||||||
path = new_path
|
path = new_path
|
||||||
video = GoZenVideo.new()
|
video = GoZenVideo.new()
|
||||||
|
|
||||||
if debug:
|
if debug:
|
||||||
video.enable_debug()
|
video.enable_debug()
|
||||||
else:
|
else:
|
||||||
video.disable_debug()
|
video.disable_debug()
|
||||||
|
|
||||||
_video_thread = WorkerThreadPool.add_task(_open_video)
|
_video_thread = WorkerThreadPool.add_task(_open_video)
|
||||||
|
|
||||||
if enable_audio:
|
if enable_audio:
|
||||||
_open_audio()
|
_open_audio()
|
||||||
|
|
||||||
|
|
||||||
## Update the video manually by providing a GoZenVideo instance and an optional AudioStreamWAV.
|
## Update the video manually by providing a GoZenVideo instance and an optional AudioStreamWAV.
|
||||||
func update_video(video_instance: GoZenVideo) -> void:
|
func update_video(video_instance: GoZenVideo, audio_stream: AudioStreamWAV = null) -> void:
|
||||||
if video != null:
|
if video != null:
|
||||||
close()
|
close()
|
||||||
|
path = video_instance.get_path()
|
||||||
_update_video(video_instance)
|
_update_video(video_instance)
|
||||||
_open_audio()
|
if audio_stream:
|
||||||
|
audio_player.stream = audio_stream
|
||||||
|
else:
|
||||||
|
_open_audio()
|
||||||
|
|
||||||
|
|
||||||
## Only run this function after manually having added a Video object to the `video` variable. A good reason for doing this is to load your video's at startup time to prevent your program for freezing for a second when loading in big video files. Some video formats load faster then others so if you are experiencing issues with long loading times, try to use this function and create the video object on startup, or try switching the video format which you are using.
|
## Only run this function after manually having added a Video object to the `video` variable. A good reason for doing this is to load your video's at startup time to prevent your program for freezing for a second when loading in big video files. Some video formats load faster then others so if you are experiencing issues with long loading times, try to use this function and create the video object on startup, or try switching the video format which you are using.
|
||||||
|
|
@ -206,7 +204,6 @@ func _update_video(new_video: GoZenVideo) -> void:
|
||||||
image = Image.create_empty(_resolution.x, _resolution.y, false, Image.FORMAT_R8)
|
image = Image.create_empty(_resolution.x, _resolution.y, false, Image.FORMAT_R8)
|
||||||
|
|
||||||
image.fill(Color.WHITE)
|
image.fill(Color.WHITE)
|
||||||
|
|
||||||
if debug:
|
if debug:
|
||||||
_print_video_debug()
|
_print_video_debug()
|
||||||
|
|
||||||
|
|
@ -240,7 +237,6 @@ func _set_color_profile(new_profile: COLOR_PROFILE = color_profile) -> void:
|
||||||
var profile_str: String = video.get_color_profile()
|
var profile_str: String = video.get_color_profile()
|
||||||
|
|
||||||
color_profile = new_profile
|
color_profile = new_profile
|
||||||
|
|
||||||
if new_profile != COLOR_PROFILE.AUTO:
|
if new_profile != COLOR_PROFILE.AUTO:
|
||||||
profile_str = str(COLOR_PROFILE.find_key(COLOR_PROFILE.BT2100)).to_lower()
|
profile_str = str(COLOR_PROFILE.find_key(COLOR_PROFILE.BT2100)).to_lower()
|
||||||
|
|
||||||
|
|
@ -248,7 +244,6 @@ func _set_color_profile(new_profile: COLOR_PROFILE = color_profile) -> void:
|
||||||
"bt2020", "bt2100": color_data = Vector4(1.4746, 0.16455, 0.57135, 1.8814)
|
"bt2020", "bt2100": color_data = Vector4(1.4746, 0.16455, 0.57135, 1.8814)
|
||||||
"bt601", "bt470": color_data = Vector4(1.402, 0.344136, 0.714136, 1.772)
|
"bt601", "bt470": color_data = Vector4(1.402, 0.344136, 0.714136, 1.772)
|
||||||
_: color_data = Vector4(1.5748, 0.1873, 0.4681, 1.8556) # bt709 and unknown
|
_: color_data = Vector4(1.5748, 0.1873, 0.4681, 1.8556) # bt709 and unknown
|
||||||
|
|
||||||
_shader_material.set_shader_parameter("color_profile", color_data)
|
_shader_material.set_shader_parameter("color_profile", color_data)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -282,7 +277,6 @@ func close() -> void:
|
||||||
if video != null:
|
if video != null:
|
||||||
if is_playing:
|
if is_playing:
|
||||||
pause()
|
pause()
|
||||||
|
|
||||||
video = null
|
video = null
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -291,7 +285,6 @@ func _process(delta: float) -> void:
|
||||||
if is_playing:
|
if is_playing:
|
||||||
_skips = 0
|
_skips = 0
|
||||||
_time_elapsed += delta
|
_time_elapsed += delta
|
||||||
|
|
||||||
if _time_elapsed < _frame_time:
|
if _time_elapsed < _frame_time:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -302,39 +295,36 @@ func _process(delta: float) -> void:
|
||||||
|
|
||||||
if current_frame >= _frame_count:
|
if current_frame >= _frame_count:
|
||||||
is_playing = !is_playing
|
is_playing = !is_playing
|
||||||
|
|
||||||
if enable_audio and audio_player.stream != null:
|
if enable_audio and audio_player.stream != null:
|
||||||
audio_player.set_stream_paused(true)
|
audio_player.set_stream_paused(true)
|
||||||
|
|
||||||
video_ended.emit()
|
video_ended.emit()
|
||||||
|
|
||||||
if loop:
|
if loop:
|
||||||
seek_frame(0)
|
seek_frame(0)
|
||||||
play()
|
play()
|
||||||
else:
|
else:
|
||||||
_sync_audio_video()
|
_sync_audio_video()
|
||||||
|
|
||||||
while _skips != 1:
|
while _skips != 1:
|
||||||
next_frame(true)
|
next_frame(true)
|
||||||
_skips -= 1
|
_skips -= 1
|
||||||
next_frame()
|
next_frame()
|
||||||
elif _video_thread != -1:
|
elif _video_thread != -1:
|
||||||
var error: int = WorkerThreadPool.wait_for_task_completion(_video_thread)
|
var error: int = WorkerThreadPool.wait_for_task_completion(_video_thread)
|
||||||
|
|
||||||
if error != OK:
|
if error != OK:
|
||||||
printerr("Something went wrong waiting for task completion! %s" % error)
|
printerr("Something went wrong waiting for task completion! %s" % error)
|
||||||
|
|
||||||
_video_thread = -1
|
_video_thread = -1
|
||||||
_update_video(video)
|
_update_video(video)
|
||||||
|
|
||||||
if enable_auto_play:
|
if enable_auto_play:
|
||||||
play()
|
play()
|
||||||
|
|
||||||
|
|
||||||
## Start the video playback. This will play until reaching the end of the video and then pause and go back to the start.
|
## Start the video playback. This will play until reaching the end of the video and then pause and go back to the start.
|
||||||
func play() -> void:
|
func play() -> void:
|
||||||
if video != null and !is_open() and is_playing:
|
if not is_open():
|
||||||
|
print("The video on '%s' isn't open yet!" % path)
|
||||||
return
|
return
|
||||||
|
if is_playing: return
|
||||||
is_playing = true
|
is_playing = true
|
||||||
|
|
||||||
if enable_audio and audio_player.stream.get_length() != 0:
|
if enable_audio and audio_player.stream.get_length() != 0:
|
||||||
|
|
@ -348,10 +338,8 @@ func play() -> void:
|
||||||
## Pausing the video.
|
## Pausing the video.
|
||||||
func pause() -> void:
|
func pause() -> void:
|
||||||
is_playing = false
|
is_playing = false
|
||||||
|
|
||||||
if enable_audio and audio_player.stream != null:
|
if enable_audio and audio_player.stream != null:
|
||||||
audio_player.set_stream_paused(true)
|
audio_player.set_stream_paused(true)
|
||||||
|
|
||||||
playback_paused.emit()
|
playback_paused.emit()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -361,7 +349,6 @@ func _sync_audio_video() -> void:
|
||||||
return
|
return
|
||||||
elif enable_audio and audio_player.stream.get_length() != 0:
|
elif enable_audio and audio_player.stream.get_length() != 0:
|
||||||
var audio_offset: float = audio_player.get_playback_position() + AudioServer.get_time_since_last_mix() - (current_frame + 1) / _frame_rate
|
var audio_offset: float = audio_player.get_playback_position() + AudioServer.get_time_since_last_mix() - (current_frame + 1) / _frame_rate
|
||||||
|
|
||||||
if abs(audio_player.get_playback_position() + AudioServer.get_time_since_last_mix() - (current_frame + 1) / _frame_rate) > AUDIO_OFFSET_THRESHOLD:
|
if abs(audio_player.get_playback_position() + AudioServer.get_time_since_last_mix() - (current_frame + 1) / _frame_rate) > AUDIO_OFFSET_THRESHOLD:
|
||||||
if debug: print("Audio Sync: time correction: ", audio_offset)
|
if debug: print("Audio Sync: time correction: ", audio_offset)
|
||||||
audio_player.seek((current_frame + 1) / _frame_rate)
|
audio_player.seek((current_frame + 1) / _frame_rate)
|
||||||
|
|
@ -451,7 +438,6 @@ func _set_frame_image() -> void:
|
||||||
RenderingServer.texture_2d_update(y_texture.get_rid(), video.get_y_data(), 0)
|
RenderingServer.texture_2d_update(y_texture.get_rid(), video.get_y_data(), 0)
|
||||||
RenderingServer.texture_2d_update(u_texture.get_rid(), video.get_u_data(), 0)
|
RenderingServer.texture_2d_update(u_texture.get_rid(), video.get_u_data(), 0)
|
||||||
RenderingServer.texture_2d_update(v_texture.get_rid(), video.get_v_data(), 0)
|
RenderingServer.texture_2d_update(v_texture.get_rid(), video.get_v_data(), 0)
|
||||||
|
|
||||||
if _has_alpha:
|
if _has_alpha:
|
||||||
RenderingServer.texture_2d_update(a_texture.get_rid(), video.get_a_data(), 0)
|
RenderingServer.texture_2d_update(a_texture.get_rid(), video.get_a_data(), 0)
|
||||||
|
|
||||||
|
|
@ -463,7 +449,6 @@ func set_playback_speed(new_playback_value: float) -> void:
|
||||||
if enable_audio and audio_player.stream != null:
|
if enable_audio and audio_player.stream != null:
|
||||||
audio_player.pitch_scale = playback_speed
|
audio_player.pitch_scale = playback_speed
|
||||||
_set_pitch_adjust()
|
_set_pitch_adjust()
|
||||||
|
|
||||||
if is_playing:
|
if is_playing:
|
||||||
audio_player.play(current_frame * (1.0 / _frame_rate))
|
audio_player.play(current_frame * (1.0 / _frame_rate))
|
||||||
|
|
||||||
|
|
@ -521,7 +506,7 @@ func _open_audio(stream_id: int = -1) -> void:
|
||||||
printerr("Failed to open AudioStreamFFmpeg for: %s" % path)
|
printerr("Failed to open AudioStreamFFmpeg for: %s" % path)
|
||||||
return
|
return
|
||||||
|
|
||||||
audio_player.set_stream.call_deferred(stream)
|
audio_player.stream = stream
|
||||||
|
|
||||||
|
|
||||||
func _print_stream_info(streams: PackedInt32Array) -> void:
|
func _print_stream_info(streams: PackedInt32Array) -> void:
|
||||||
|
|
@ -565,22 +550,19 @@ func _print_video_debug() -> void:
|
||||||
print("Using sws: ", video.is_using_sws())
|
print("Using sws: ", video.is_using_sws())
|
||||||
print("Sar: ", video.get_sar())
|
print("Sar: ", video.get_sar())
|
||||||
|
|
||||||
if video_streams.size() != 0:
|
print_rich("Video streams: [i](%s)" % video_streams.size())
|
||||||
print_rich("Video streams: [i](%s)" % video_streams.size())
|
_print_stream_info(video_streams)
|
||||||
_print_stream_info(video_streams)
|
|
||||||
else:
|
|
||||||
print("No video streams found.")
|
|
||||||
|
|
||||||
if audio_streams.size() != 0:
|
if audio_streams.size() != 0:
|
||||||
print_rich("Audio streams: [i](%s)" % audio_streams.size())
|
print_rich("Audio streams: [i](%s)" % audio_streams.size())
|
||||||
_print_stream_info(audio_streams)
|
_print_stream_info(audio_streams)
|
||||||
else:
|
elif debug:
|
||||||
print("No audio streams found.")
|
print("No audio streams found.")
|
||||||
|
|
||||||
if subtitle_streams.size() != 0:
|
if subtitle_streams.size() != 0:
|
||||||
print_rich("Subtitle streams: [i](%s)" % subtitle_streams.size())
|
print_rich("Subtitle streams: [i](%s)" % subtitle_streams.size())
|
||||||
_print_stream_info(subtitle_streams)
|
_print_stream_info(subtitle_streams)
|
||||||
else:
|
elif debug:
|
||||||
print("No subtitle streams found.")
|
print("No subtitle streams found.")
|
||||||
|
|
||||||
if chapters.size() != 0:
|
if chapters.size() != 0:
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,14 @@ signal event_received(event: Message)
|
||||||
signal _auth_required()
|
signal _auth_required()
|
||||||
|
|
||||||
|
|
||||||
|
func is_open() -> bool:
|
||||||
|
return _ws != null and _ws.get_ready_state() == WebSocketPeer.STATE_OPEN
|
||||||
|
|
||||||
func connect_to_obsws(port: int, host: String = "127.0.0.1", password: String = "") -> void:
|
func connect_to_obsws(port: int, host: String = "127.0.0.1", password: String = "") -> void:
|
||||||
_ws = WebSocketPeer.new()
|
_ws = WebSocketPeer.new()
|
||||||
_ws.connect_to_url(WS_URL % [host,port])
|
_ws.connect_to_url(WS_URL % [host,port])
|
||||||
_auth_required.connect(_authenticate.bind(password))
|
if not _auth_required.is_connected(_authenticate):
|
||||||
|
_auth_required.connect(_authenticate.bind(password))
|
||||||
|
|
||||||
|
|
||||||
func disconnect_from_obsws() -> void:
|
func disconnect_from_obsws() -> void:
|
||||||
|
|
|
||||||
4
default_bus_layout.tres
Normal file
4
default_bus_layout.tres
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
[gd_resource type="AudioBusLayout" format=3 uid="uid://byd4lkofdecc0"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
bus/0/volume_db = -9.632782
|
||||||
|
|
@ -2,11 +2,25 @@ extends Node
|
||||||
|
|
||||||
var ol: OverlayWindow
|
var ol: OverlayWindow
|
||||||
|
|
||||||
|
var _queue: Array[Alert] = []
|
||||||
|
|
||||||
# Called when the node enters the scene tree for the first time.
|
# Called when the node enters the scene tree for the first time.
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
ol = get_tree().root.get_node("MainWin")
|
if get_tree().root.has_node("MainWin"):
|
||||||
|
ol = get_tree().root.get_node("MainWin")
|
||||||
|
|
||||||
|
func add_alert(alert: Alert) -> void:
|
||||||
|
if get_children().any(func(x): return x is Alert):
|
||||||
|
_queue.append(alert)
|
||||||
|
else:
|
||||||
|
add_child(alert)
|
||||||
|
|
||||||
|
func _process(_d: float) -> void:
|
||||||
|
if _queue.is_empty(): return
|
||||||
|
if get_children().any(func(x): return x is Alert):
|
||||||
|
return
|
||||||
|
var alert: Alert = _queue.pop_front()
|
||||||
|
add_child(alert)
|
||||||
|
|
||||||
func test_notification(msg: String) -> void:
|
func test_notification(msg: String) -> void:
|
||||||
var lbl = Label.new()
|
var lbl = Label.new()
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ extends Node
|
||||||
var twitcher: TwitcherExtended
|
var twitcher: TwitcherExtended
|
||||||
var context: OverlayContext
|
var context: OverlayContext
|
||||||
var settings: OverlaySettings
|
var settings: OverlaySettings
|
||||||
|
var main_win: OverlayWindow
|
||||||
var _pt_except: Array[Control] = []
|
var _pt_except: Array[Control] = []
|
||||||
var _pt_mouse: bool = false
|
var _pt_mouse: bool = false
|
||||||
var _current_pt_mask: PackedVector2Array = []
|
var _current_pt_mask: PackedVector2Array = []
|
||||||
|
|
|
||||||
167
lib/obs_manager.gd
Normal file
167
lib/obs_manager.gd
Normal file
|
|
@ -0,0 +1,167 @@
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
var obs: NoOBSWS
|
||||||
|
signal obs_ready()
|
||||||
|
signal obs_disconnect()
|
||||||
|
signal stream_state_changed(state: bool)
|
||||||
|
signal input_state_changed(input_name: String, state: bool)
|
||||||
|
signal scene_changed(scene_name: String, scene_uuid: String)
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _ready() -> void:
|
||||||
|
obs = NoOBSWS.new()
|
||||||
|
add_child(obs)
|
||||||
|
obs.event_received.connect(_handle_websock_events)
|
||||||
|
obs.connection_ready.connect(obs_ready.emit)
|
||||||
|
obs.connection_closed_clean.connect(_handle_disconnect)
|
||||||
|
|
||||||
|
func is_open() -> bool:
|
||||||
|
return obs.is_open()
|
||||||
|
|
||||||
|
func connect_to_host() -> void:
|
||||||
|
if not (Globals.settings.obs_host != "" and
|
||||||
|
Globals.settings.obs_port != 0 and
|
||||||
|
Globals.settings.obs_pass != ""):
|
||||||
|
return
|
||||||
|
|
||||||
|
obs.connect_to_obsws(Globals.settings.obs_port, Globals.settings.obs_host, Globals.settings.obs_pass)
|
||||||
|
|
||||||
|
func _handle_disconnect(reason: int, message: String) -> void:
|
||||||
|
obs_disconnect.emit()
|
||||||
|
if Globals.settings.obs_reconnect:
|
||||||
|
connect_to_host()
|
||||||
|
|
||||||
|
func _handle_websock_events(event: NoOBSWS.Message) -> void:
|
||||||
|
var data := event.get_data()
|
||||||
|
if data.has("event_type"):
|
||||||
|
if not data.has("event_data"):
|
||||||
|
return
|
||||||
|
var ed: Dictionary = data.event_data
|
||||||
|
match data.event_type:
|
||||||
|
"StreamStateChanged":
|
||||||
|
stream_state_changed.emit(ed.output_active)
|
||||||
|
"InputMuteStateChanged":
|
||||||
|
input_state_changed.emit(ed.input_name, ed.input_muted)
|
||||||
|
"CurrentProgramSceneChanged":
|
||||||
|
scene_changed.emit(ed.scene_name, ed.scene_uuid)
|
||||||
|
|
||||||
|
|
||||||
|
func get_stream_status() -> bool:
|
||||||
|
var request_type := "GetStreamStatus"
|
||||||
|
var request := obs.make_generic_request(request_type)
|
||||||
|
await request.response_received
|
||||||
|
var response = request.message.get_data()
|
||||||
|
return response.response_data.output_active as bool
|
||||||
|
|
||||||
|
|
||||||
|
func get_scene_item_id(scene_name: String, source_name: String) -> int:
|
||||||
|
var request_type := "GetSceneItemId"
|
||||||
|
var request_data := {"scene_name": scene_name, "source_name": source_name}
|
||||||
|
var request := obs.make_generic_request(request_type, request_data)
|
||||||
|
await request.response_received
|
||||||
|
var response = request.message.get_data()
|
||||||
|
return response.response_data.scene_item_id as int
|
||||||
|
|
||||||
|
|
||||||
|
func get_item_enabled(scene_name: String, item_id: int) -> bool:
|
||||||
|
var request_type = "GetSceneItemEnabled"
|
||||||
|
var request_data = {"scene_name": scene_name, "scene_item_id": item_id}
|
||||||
|
var request = obs.make_generic_request(request_type, request_data)
|
||||||
|
await request.response_received
|
||||||
|
var response = request.message.get_data()
|
||||||
|
return response.response_data.scene_item_enabled as bool
|
||||||
|
|
||||||
|
|
||||||
|
func set_item_enabled(scene_name: String, item_id: int, val: bool) -> void:
|
||||||
|
var request_type = "SetSceneItemEnabled"
|
||||||
|
var request_data = {"scene_name": scene_name, "scene_item_id": item_id, "scene_item_enabled": val}
|
||||||
|
obs.make_generic_request(request_type, request_data)
|
||||||
|
|
||||||
|
|
||||||
|
func get_item_transform(scene_name: String, item_id: int) -> Dictionary:
|
||||||
|
var request_type = "GetSceneItemTransform"
|
||||||
|
var request_data = {"scene_name": scene_name, "scene_item_id": item_id}
|
||||||
|
var request = obs.make_generic_request(request_type, request_data)
|
||||||
|
await request.response_received
|
||||||
|
var response = request.message.get_data()
|
||||||
|
return response.response_data.scene_item_transform as Dictionary
|
||||||
|
|
||||||
|
|
||||||
|
func set_item_transform(scene_name: String, item_id: int, transform: Dictionary) -> void:
|
||||||
|
var request_type = "SetSceneItemTransform"
|
||||||
|
var request_data = {"scene_name": scene_name, "scene_item_id": item_id, "scene_item_transform": transform}
|
||||||
|
obs.make_generic_request(request_type, request_data)
|
||||||
|
|
||||||
|
|
||||||
|
func get_input_mute(input_name: String) -> bool:
|
||||||
|
var request_type = "GetInputMute"
|
||||||
|
var request_data = {"input_name": input_name}
|
||||||
|
var request = obs.make_generic_request(request_type, request_data)
|
||||||
|
await request.response_received
|
||||||
|
var response = request.message.get_data()
|
||||||
|
return response.response_data.input_muted
|
||||||
|
|
||||||
|
|
||||||
|
func set_input_mute(input_name: String, val: bool) -> void:
|
||||||
|
var request_type = "SetInputMute"
|
||||||
|
var request_data = {"input_name": input_name, "input_muted": val}
|
||||||
|
obs.make_generic_request(request_type, request_data)
|
||||||
|
|
||||||
|
|
||||||
|
func get_item_filter_enabled(source_name: String, filter_name: String) -> bool:
|
||||||
|
var request_type = "GetSourceFilter"
|
||||||
|
var request_data = {
|
||||||
|
"source_name": source_name,
|
||||||
|
"filter_name": filter_name
|
||||||
|
}
|
||||||
|
var request = obs.make_generic_request(request_type, request_data)
|
||||||
|
await request.response_received
|
||||||
|
var response = request.message.get_data()
|
||||||
|
return response.response_data.filter_enabled
|
||||||
|
|
||||||
|
|
||||||
|
func set_item_filter_enabled(source_name: String, filter_name: String, filter_enabled: bool) -> void:
|
||||||
|
var request_type = "SetSourceFilterEnabled"
|
||||||
|
var request_data = {
|
||||||
|
"source_name": source_name,
|
||||||
|
"filter_name": filter_name,
|
||||||
|
"filter_enabled": filter_enabled
|
||||||
|
}
|
||||||
|
obs.make_generic_request(request_type, request_data)
|
||||||
|
|
||||||
|
|
||||||
|
func get_item_filter_setting(source_name: String, filter_name: String) -> Dictionary:
|
||||||
|
var request_type = "GetSourceFilter"
|
||||||
|
var request_data = {
|
||||||
|
"source_name": source_name,
|
||||||
|
"filter_name": filter_name
|
||||||
|
}
|
||||||
|
var request = obs.make_generic_request(request_type, request_data)
|
||||||
|
await request.response_received
|
||||||
|
var response = request.message.get_data()
|
||||||
|
return response.response_data.filter_settings
|
||||||
|
|
||||||
|
|
||||||
|
func set_item_filter_setting(source_name: String, filter_name: String, filter_settings: Dictionary) -> void:
|
||||||
|
var request_type = "SetSourceFilterSettings"
|
||||||
|
var request_data = {
|
||||||
|
"sourceName": source_name,
|
||||||
|
"filterName": filter_name,
|
||||||
|
"filterSettings": filter_settings,
|
||||||
|
"overlay": true
|
||||||
|
}
|
||||||
|
var res: NoOBSWS.RequestResponse = obs.make_generic_request(request_type, request_data)
|
||||||
|
await res.response_received
|
||||||
|
|
||||||
|
|
||||||
|
func stop_stream() -> void:
|
||||||
|
var request_type = "StopStream"
|
||||||
|
var request_data = {}
|
||||||
|
var request = obs.make_generic_request(request_type, request_data)
|
||||||
|
await request.response_received
|
||||||
|
|
||||||
|
|
||||||
|
func restart_media(media_name) -> void:
|
||||||
|
var request_type = "TriggerMediaInputAction"
|
||||||
|
var request_data = {"input_name": media_name, "media_action": "OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART"}
|
||||||
|
var request = obs.make_generic_request(request_type, request_data)
|
||||||
|
await request.response_received
|
||||||
1
lib/obs_manager.gd.uid
Normal file
1
lib/obs_manager.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://c447ij3oc24q3
|
||||||
|
|
@ -3,7 +3,19 @@ class_name OverlaySettings
|
||||||
|
|
||||||
@export var auto_connect_twitch: bool = false
|
@export var auto_connect_twitch: bool = false
|
||||||
@export var auto_connect_obs: bool = false
|
@export var auto_connect_obs: bool = false
|
||||||
|
|
||||||
|
@export var obs_path: String = "/usr/bin/obs"
|
||||||
|
@export var obs_name: String = "obs"
|
||||||
@export var obs_host: String = "localhost"
|
@export var obs_host: String = "localhost"
|
||||||
@export var obs_port: int = 4455
|
@export var obs_port: int = 4455
|
||||||
@export var obs_pass: String = ""
|
@export var obs_pass: String = ""
|
||||||
|
@export var obs_reconnect: bool = false
|
||||||
|
|
||||||
|
@export var vtuber_path: String = "/home/eumario/apps/veadotube-labs-veadotube-linux-x64/veadotube.sh"
|
||||||
|
@export var vtuber_name: String = "veadotube"
|
||||||
|
@export var vtuber_model_path: String = "/home/eumario/Pictures/PNGTuber/cdw3/main_scene.veadoscene"
|
||||||
|
|
||||||
|
@export var display_screen: int = -1
|
||||||
|
|
||||||
|
|
||||||
@export var script_storage: Dictionary
|
@export var script_storage: Dictionary
|
||||||
|
|
|
||||||
81
lib/process_tree.gd
Normal file
81
lib/process_tree.gd
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
extends RefCounted
|
||||||
|
class_name ProcessTree
|
||||||
|
|
||||||
|
class ProcessInfo:
|
||||||
|
extends RefCounted
|
||||||
|
## Class representing a shallow base of Process information for a process running on the system.
|
||||||
|
|
||||||
|
## User ID that ran this process
|
||||||
|
var uid: int
|
||||||
|
## ID for the System processs
|
||||||
|
var pid: int
|
||||||
|
## Parent process that executed this ID.
|
||||||
|
var ppid: int
|
||||||
|
## Executable that was used to run this process.
|
||||||
|
var executable: String
|
||||||
|
|
||||||
|
func _init(_user: String, _pid: String, _ppid: String, name: String) -> void:
|
||||||
|
uid = _user.to_int()
|
||||||
|
pid = _pid.to_int()
|
||||||
|
ppid = _ppid.to_int()
|
||||||
|
executable = name
|
||||||
|
|
||||||
|
func _to_string() -> String:
|
||||||
|
return "<ProcessInfo: pid:%d, ppid:%d, user:%d, exec:%s>" % [pid, ppid, uid, executable]
|
||||||
|
|
||||||
|
## Returns true/false if the process is currently running
|
||||||
|
func is_running() -> bool:
|
||||||
|
return OS.is_process_running(pid)
|
||||||
|
|
||||||
|
## Kills the process on the system.
|
||||||
|
func kill() -> Error:
|
||||||
|
return OS.kill(pid)
|
||||||
|
|
||||||
|
## Kills the parent process that ran this process. (NOTE: May kill this process, or leave this process in a Zombie State)
|
||||||
|
func kill_parent() -> Error:
|
||||||
|
return OS.kill(ppid)
|
||||||
|
|
||||||
|
var processes: Array[ProcessInfo] = []
|
||||||
|
|
||||||
|
func _init() -> void:
|
||||||
|
refresh()
|
||||||
|
|
||||||
|
func refresh() -> void:
|
||||||
|
processes.clear()
|
||||||
|
var output := []
|
||||||
|
OS.execute("/usr/bin/ps", ["-eo", "uid,pid,ppid,exe"], output)
|
||||||
|
var lines: PackedStringArray = output[0].split("\n")
|
||||||
|
for line in lines:
|
||||||
|
var parts = line.split(" ",false,4)
|
||||||
|
if parts.is_empty(): continue
|
||||||
|
if parts[0] == "UID":
|
||||||
|
continue
|
||||||
|
if parts[3] == "-":
|
||||||
|
continue
|
||||||
|
var proc: ProcessInfo = ProcessInfo.new(parts[0],parts[1],parts[2],parts[3])
|
||||||
|
processes.append(proc)
|
||||||
|
|
||||||
|
func has_process_id(id: int) -> bool:
|
||||||
|
return processes.any(func(x: ProcessInfo): return x.pid == id)
|
||||||
|
|
||||||
|
func has_process_name(name: String) -> bool:
|
||||||
|
return processes.any(func(x: ProcessInfo): return x.executable == name or name in x.executable)
|
||||||
|
|
||||||
|
func get_process(id: int) -> ProcessInfo:
|
||||||
|
for proc: ProcessInfo in processes:
|
||||||
|
if proc.pid == id:
|
||||||
|
return proc
|
||||||
|
return null
|
||||||
|
|
||||||
|
func get_process_by_name(name: String) -> ProcessInfo:
|
||||||
|
for proc: ProcessInfo in processes:
|
||||||
|
if proc.executable == name or name in proc.executable:
|
||||||
|
return proc
|
||||||
|
return null
|
||||||
|
|
||||||
|
func get_all_processes_by_name(name: String) -> Array[ProcessInfo]:
|
||||||
|
var procs: Array[ProcessInfo] = []
|
||||||
|
for proc: ProcessInfo in processes:
|
||||||
|
if proc.executable == name or name in proc.executable:
|
||||||
|
procs.append(proc)
|
||||||
|
return procs
|
||||||
1
lib/process_tree.gd.uid
Normal file
1
lib/process_tree.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://d1wr43cirxvbn
|
||||||
|
|
@ -57,6 +57,8 @@ static var instance: TwitcherExtended
|
||||||
#region Public Variables
|
#region Public Variables
|
||||||
var streamer_user: TwitchUser
|
var streamer_user: TwitchUser
|
||||||
var bot_user: TwitchUser
|
var bot_user: TwitchUser
|
||||||
|
var streamer_token_loaded: bool = false
|
||||||
|
var chatbot_token_loaded: bool = false
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Private Variables
|
#region Private Variables
|
||||||
|
|
@ -184,15 +186,19 @@ func _twitcher_setup() -> void:
|
||||||
#region Streamer Public Functions
|
#region Streamer Public Functions
|
||||||
func load_streamer_token() -> AuthStatus:
|
func load_streamer_token() -> AuthStatus:
|
||||||
_log.d("Loading streamer tokens...")
|
_log.d("Loading streamer tokens...")
|
||||||
|
streamer_token_loaded = false
|
||||||
var res = streamer_token._load_tokens()
|
var res = streamer_token._load_tokens()
|
||||||
if not res:
|
if not res:
|
||||||
_log.d("Token doesn't exist")
|
_log.d("Token doesn't exist")
|
||||||
return AuthStatus.UNAUTHORIZED
|
return AuthStatus.UNAUTHORIZED
|
||||||
if streamer_token.is_token_valid():
|
if streamer_token.is_token_valid():
|
||||||
_log.d("Token authorized")
|
_log.d("Token authorized")
|
||||||
|
streamer_user = await service.get_current_user()
|
||||||
|
streamer_token_loaded = true
|
||||||
return AuthStatus.AUTHORIZED
|
return AuthStatus.AUTHORIZED
|
||||||
if streamer_token.has_refresh_token():
|
if streamer_token.has_refresh_token():
|
||||||
_log.d("Token needs refreshed")
|
_log.d("Token needs refreshed")
|
||||||
|
streamer_token_loaded = true
|
||||||
return AuthStatus.NEEDS_REFRESH
|
return AuthStatus.NEEDS_REFRESH
|
||||||
_log.d("Token invalid")
|
_log.d("Token invalid")
|
||||||
return AuthStatus.UNAUTHORIZED
|
return AuthStatus.UNAUTHORIZED
|
||||||
|
|
@ -244,15 +250,19 @@ func setup_streamer() -> bool:
|
||||||
#region Chatbot Functions
|
#region Chatbot Functions
|
||||||
func load_chatbot_token() -> AuthStatus:
|
func load_chatbot_token() -> AuthStatus:
|
||||||
_log.d("Loading chatbot tokens...")
|
_log.d("Loading chatbot tokens...")
|
||||||
|
chatbot_token_loaded = false
|
||||||
var res = chatbot_token._load_tokens()
|
var res = chatbot_token._load_tokens()
|
||||||
if not res:
|
if not res:
|
||||||
_log.d("Token doesn't exist")
|
_log.d("Token doesn't exist")
|
||||||
return AuthStatus.UNAUTHORIZED
|
return AuthStatus.UNAUTHORIZED
|
||||||
if chatbot_token.is_token_valid():
|
if chatbot_token.is_token_valid():
|
||||||
_log.d("Token authroized")
|
_log.d("Token authroized")
|
||||||
|
bot_user = await chatbot_auth.get_user()
|
||||||
|
chatbot_token_loaded = true
|
||||||
return AuthStatus.AUTHORIZED
|
return AuthStatus.AUTHORIZED
|
||||||
if chatbot_token.has_refresh_token():
|
if chatbot_token.has_refresh_token():
|
||||||
_log.d("Token needs refreshed")
|
_log.d("Token needs refreshed")
|
||||||
|
chatbot_token_loaded = true
|
||||||
return AuthStatus.NEEDS_REFRESH
|
return AuthStatus.NEEDS_REFRESH
|
||||||
_log.d("Token invalid")
|
_log.d("Token invalid")
|
||||||
return AuthStatus.UNAUTHORIZED
|
return AuthStatus.UNAUTHORIZED
|
||||||
|
|
|
||||||
55
main_win.gd
55
main_win.gd
|
|
@ -8,23 +8,56 @@ class_name OverlayWindow
|
||||||
@onready var twitcher: TwitcherExtended = $TwitcherExtended
|
@onready var twitcher: TwitcherExtended = $TwitcherExtended
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@export var subscriptions: Array[TwitchEventsubConfig] = []
|
||||||
|
|
||||||
# Called when the node enters the scene tree for the first time.
|
# Called when the node enters the scene tree for the first time.
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
Globals.main_win = self
|
||||||
Globals.add_children_to_passthrough_exception(floating_menu, [floating_menu.indicators])
|
Globals.add_children_to_passthrough_exception(floating_menu, [floating_menu.indicators])
|
||||||
Globals.enable_mouse_passthrough()
|
Globals.enable_mouse_passthrough()
|
||||||
floating_menu.start()
|
floating_menu.start()
|
||||||
Globals.twitcher = twitcher
|
Globals.twitcher = twitcher
|
||||||
|
if Globals.settings.display_screen != -1:
|
||||||
|
get_window().current_screen = Globals.settings.display_screen
|
||||||
|
|
||||||
var res := twitcher.load_streamer_token()
|
if Globals.settings.auto_connect_twitch:
|
||||||
if res == TwitcherExtended.AuthStatus.UNAUTHORIZED:
|
var res := await twitcher.load_streamer_token()
|
||||||
return
|
if res == TwitcherExtended.AuthStatus.UNAUTHORIZED:
|
||||||
|
return
|
||||||
|
|
||||||
func _handle_twitch_auth() -> void:
|
if await twitcher.setup_streamer():
|
||||||
await twitcher.setup_streamer()
|
for sub in subscriptions:
|
||||||
#if twitcher.is_streamer_authed():
|
if sub.condition.has(&"broadcaster_user_id"):
|
||||||
#auth_twitch.disabled = true
|
sub.condition.broadcaster_user_id = twitcher.streamer_user.id
|
||||||
|
if sub.condition.has(&"moderator_user_id"):
|
||||||
|
sub.condition.moderator_user_id = twitcher.streamer_user.id
|
||||||
|
if sub.condition.has(&"to_broadcaster_user_id"):
|
||||||
|
sub.condition.to_broadcaster_user_id = twitcher.streamer_user.id
|
||||||
|
|
||||||
func _handle_bot_auth() -> void:
|
twitcher.subscribe_event(sub.definition, sub.condition)
|
||||||
await twitcher.setup_chatbot()
|
|
||||||
#if twitcher.is_chatbot_authed():
|
res = await twitcher.load_chatbot_token()
|
||||||
#auth_bot.disabled = true
|
if res == TwitcherExtended.AuthStatus.UNAUTHORIZED:
|
||||||
|
return
|
||||||
|
twitcher.setup_chatbot()
|
||||||
|
|
||||||
|
ObsManager.scene_changed.connect(_handle_scene_changed)
|
||||||
|
|
||||||
|
if Globals.settings.auto_connect_obs:
|
||||||
|
ObsManager.connect_to_host()
|
||||||
|
pass
|
||||||
|
|
||||||
|
func _handle_scene_changed(scene_name: String, scene_uuid: String) -> void:
|
||||||
|
match scene_name:
|
||||||
|
"StartingSoon":
|
||||||
|
%ChatBox.dock = ChatBox.ChatDock.RIGHT
|
||||||
|
"Talking":
|
||||||
|
%ChatBox.dock = ChatBox.ChatDock.RIGHT
|
||||||
|
"Desktop":
|
||||||
|
%ChatBox.dock = ChatBox.ChatDock.BOTTOM
|
||||||
|
"Gaming":
|
||||||
|
%ChatBox.dock = ChatBox.ChatDock.RIGHT
|
||||||
|
"BRB":
|
||||||
|
%ChatBox.dock = ChatBox.ChatDock.RIGHT
|
||||||
|
"EndingSoon":
|
||||||
|
%ChatBox.dock = ChatBox.ChatDock.RIGHT
|
||||||
|
|
|
||||||
108
main_win.tscn
108
main_win.tscn
|
|
@ -18,15 +18,118 @@
|
||||||
[ext_resource type="Texture2D" uid="uid://g1dbcjksbotw" path="res://addons/twitcher/assets/fallback_texture.tres" id="13_l81bt"]
|
[ext_resource type="Texture2D" uid="uid://g1dbcjksbotw" path="res://addons/twitcher/assets/fallback_texture.tres" id="13_l81bt"]
|
||||||
[ext_resource type="Script" uid="uid://6v8jnfjwbnhm" path="res://addons/twitcher/media/twitch_image_transformer.gd" id="14_dr7ot"]
|
[ext_resource type="Script" uid="uid://6v8jnfjwbnhm" path="res://addons/twitcher/media/twitch_image_transformer.gd" id="14_dr7ot"]
|
||||||
[ext_resource type="Script" uid="uid://iv0mgv0lu8b0" path="res://addons/twitcher/auth/twitch_auth.gd" id="14_l81bt"]
|
[ext_resource type="Script" uid="uid://iv0mgv0lu8b0" path="res://addons/twitcher/auth/twitch_auth.gd" id="14_l81bt"]
|
||||||
|
[ext_resource type="Script" uid="uid://cjug64e3433g0" path="res://addons/twitcher/eventsub/twitch_eventsub_config.gd" id="14_vifpv"]
|
||||||
[ext_resource type="Resource" uid="uid://b8735fmqjt8up" path="res://addons/twitcher/chat/twitch_bot_scopes.tres" id="15_dr7ot"]
|
[ext_resource type="Resource" uid="uid://b8735fmqjt8up" path="res://addons/twitcher/chat/twitch_bot_scopes.tres" id="15_dr7ot"]
|
||||||
[ext_resource type="Script" uid="uid://bf0wi70haua35" path="res://addons/twitcher/lib/oOuch/oauth.gd" id="16_m7rpr"]
|
[ext_resource type="Script" uid="uid://bf0wi70haua35" path="res://addons/twitcher/lib/oOuch/oauth.gd" id="16_m7rpr"]
|
||||||
[ext_resource type="Script" uid="uid://blnbogtrshw4r" path="res://addons/twitcher/auth/twitch_token_handler.gd" id="17_lpeoe"]
|
[ext_resource type="Script" uid="uid://blnbogtrshw4r" path="res://addons/twitcher/auth/twitch_token_handler.gd" id="17_lpeoe"]
|
||||||
[ext_resource type="Script" uid="uid://csq2hmf1bsgku" path="res://lib/twitcher_extended/chatbot_authorization.gd" id="18_vifpv"]
|
[ext_resource type="Script" uid="uid://csq2hmf1bsgku" path="res://lib/twitcher_extended/chatbot_authorization.gd" id="18_vifpv"]
|
||||||
[ext_resource type="PackedScene" uid="uid://djdxpwrmlrsp8" path="res://ChatAvatars/CatSlimes/cat_world.tscn" id="23_7nx26"]
|
[ext_resource type="PackedScene" uid="uid://djdxpwrmlrsp8" path="res://ChatAvatars/CatSlimes/cat_world.tscn" id="23_7nx26"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://cstq30mjx0pch" path="res://UI/Controls/chat_box.tscn" id="23_lpeoe"]
|
||||||
[ext_resource type="Script" uid="uid://cv06lthuq2c2o" path="res://general_commands.gd" id="24_dr7ot"]
|
[ext_resource type="Script" uid="uid://cv06lthuq2c2o" path="res://general_commands.gd" id="24_dr7ot"]
|
||||||
[ext_resource type="Script" uid="uid://bmluckfvgm1c2" path="res://addons/twitcher/chat/twitch_command.gd" id="24_l81bt"]
|
[ext_resource type="Script" uid="uid://bmluckfvgm1c2" path="res://addons/twitcher/chat/twitch_command.gd" id="24_l81bt"]
|
||||||
[ext_resource type="PackedScene" uid="uid://bndydwe6rrb6p" path="res://UI/floating_menu.tscn" id="26_m7rpr"]
|
[ext_resource type="PackedScene" uid="uid://bndydwe6rrb6p" path="res://UI/floating_menu.tscn" id="26_m7rpr"]
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_1scbk"]
|
||||||
|
script = ExtResource("14_vifpv")
|
||||||
|
type = 15
|
||||||
|
condition = {
|
||||||
|
&"broadcaster_user_id": ""
|
||||||
|
}
|
||||||
|
metadata/_custom_type_script = "uid://cjug64e3433g0"
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_dqy2v"]
|
||||||
|
script = ExtResource("14_vifpv")
|
||||||
|
type = 17
|
||||||
|
condition = {
|
||||||
|
&"broadcaster_user_id": ""
|
||||||
|
}
|
||||||
|
metadata/_custom_type_script = "uid://cjug64e3433g0"
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_7ft7d"]
|
||||||
|
script = ExtResource("14_vifpv")
|
||||||
|
type = 18
|
||||||
|
condition = {
|
||||||
|
&"broadcaster_user_id": ""
|
||||||
|
}
|
||||||
|
metadata/_custom_type_script = "uid://cjug64e3433g0"
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_84aqx"]
|
||||||
|
script = ExtResource("14_vifpv")
|
||||||
|
type = 5
|
||||||
|
condition = {
|
||||||
|
&"broadcaster_user_id": "",
|
||||||
|
&"moderator_user_id": ""
|
||||||
|
}
|
||||||
|
metadata/_custom_type_script = "uid://cjug64e3433g0"
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_es602"]
|
||||||
|
script = ExtResource("14_vifpv")
|
||||||
|
type = 20
|
||||||
|
condition = {
|
||||||
|
&"to_broadcaster_user_id": ""
|
||||||
|
}
|
||||||
|
metadata/_custom_type_script = "uid://cjug64e3433g0"
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_s0vyq"]
|
||||||
|
script = ExtResource("14_vifpv")
|
||||||
|
type = 21
|
||||||
|
condition = {
|
||||||
|
&"broadcaster_user_id": ""
|
||||||
|
}
|
||||||
|
metadata/_custom_type_script = "uid://cjug64e3433g0"
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_vwie2"]
|
||||||
|
script = ExtResource("14_vifpv")
|
||||||
|
type = 37
|
||||||
|
condition = {
|
||||||
|
&"broadcaster_user_id": "",
|
||||||
|
&"reward_id": ""
|
||||||
|
}
|
||||||
|
metadata/_custom_type_script = "uid://cjug64e3433g0"
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_qp6p1"]
|
||||||
|
script = ExtResource("14_vifpv")
|
||||||
|
type = 38
|
||||||
|
condition = {
|
||||||
|
&"broadcaster_user_id": "",
|
||||||
|
&"reward_id": ""
|
||||||
|
}
|
||||||
|
metadata/_custom_type_script = "uid://cjug64e3433g0"
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_2a87i"]
|
||||||
|
script = ExtResource("14_vifpv")
|
||||||
|
type = 64
|
||||||
|
condition = {
|
||||||
|
&"broadcaster_user_id": "",
|
||||||
|
&"moderator_user_id": ""
|
||||||
|
}
|
||||||
|
metadata/_custom_type_script = "uid://cjug64e3433g0"
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_do4qx"]
|
||||||
|
script = ExtResource("14_vifpv")
|
||||||
|
type = 65
|
||||||
|
condition = {
|
||||||
|
&"broadcaster_user_id": "",
|
||||||
|
&"moderator_user_id": ""
|
||||||
|
}
|
||||||
|
metadata/_custom_type_script = "uid://cjug64e3433g0"
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_dgy7a"]
|
||||||
|
script = ExtResource("14_vifpv")
|
||||||
|
type = 6
|
||||||
|
condition = {
|
||||||
|
&"broadcaster_user_id": ""
|
||||||
|
}
|
||||||
|
metadata/_custom_type_script = "uid://cjug64e3433g0"
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_qh6mc"]
|
||||||
|
script = ExtResource("14_vifpv")
|
||||||
|
condition = {
|
||||||
|
&"broadcaster_user_id": "",
|
||||||
|
&"moderator_user_id": ""
|
||||||
|
}
|
||||||
|
metadata/_custom_type_script = "uid://cjug64e3433g0"
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Resource_m7rpr"]
|
[sub_resource type="Resource" id="Resource_m7rpr"]
|
||||||
script = ExtResource("14_dr7ot")
|
script = ExtResource("14_dr7ot")
|
||||||
|
|
||||||
|
|
@ -52,6 +155,11 @@ anchor_bottom = 1.0
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
script = ExtResource("1_bgu0c")
|
script = ExtResource("1_bgu0c")
|
||||||
|
subscriptions = Array[ExtResource("14_vifpv")]([SubResource("Resource_1scbk"), SubResource("Resource_dqy2v"), SubResource("Resource_7ft7d"), SubResource("Resource_84aqx"), SubResource("Resource_es602"), SubResource("Resource_s0vyq"), SubResource("Resource_vwie2"), SubResource("Resource_qp6p1"), SubResource("Resource_2a87i"), SubResource("Resource_do4qx"), SubResource("Resource_dgy7a"), SubResource("Resource_qh6mc")])
|
||||||
|
|
||||||
|
[node name="ChatBox" parent="." unique_id=859214320 instance=ExtResource("23_lpeoe")]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 1
|
||||||
|
|
||||||
[node name="TwitcherExtended" type="Node" parent="." unique_id=1225944144 node_paths=PackedStringArray("service", "chat", "bot", "chatbot_auth", "eventsub", "api", "auth", "media")]
|
[node name="TwitcherExtended" type="Node" parent="." unique_id=1225944144 node_paths=PackedStringArray("service", "chat", "bot", "chatbot_auth", "eventsub", "api", "auth", "media")]
|
||||||
script = ExtResource("2_x1kh3")
|
script = ExtResource("2_x1kh3")
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,14 @@ config/description="Enter an interesting project description here!"
|
||||||
run/main_scene="uid://2t2hslaaewee"
|
run/main_scene="uid://2t2hslaaewee"
|
||||||
config/features=PackedStringArray("4.6")
|
config/features=PackedStringArray("4.6")
|
||||||
config/icon="res://icon.png"
|
config/icon="res://icon.png"
|
||||||
|
run/custom_runner=""
|
||||||
|
|
||||||
[autoload]
|
[autoload]
|
||||||
|
|
||||||
Globals="*uid://cuap0k5jagdtj"
|
Globals="*uid://cuap0k5jagdtj"
|
||||||
ChatManager="*uid://ct1s5eymb8mns"
|
ChatManager="*uid://ct1s5eymb8mns"
|
||||||
EventManager="*uid://cvjhecj1me4xl"
|
EventManager="*uid://cvjhecj1me4xl"
|
||||||
|
ObsManager="*uid://c447ij3oc24q3"
|
||||||
|
|
||||||
[display]
|
[display]
|
||||||
|
|
||||||
|
|
|
||||||
94
tools/pt_testing.gd
Normal file
94
tools/pt_testing.gd
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
@tool
|
||||||
|
extends EditorScript
|
||||||
|
|
||||||
|
var finds: Array = [
|
||||||
|
"kitty",
|
||||||
|
"/opt/zen-browser-bin/zen-bin",
|
||||||
|
"zen-bin",
|
||||||
|
"bin/dolphin",
|
||||||
|
"Discord",
|
||||||
|
"discord"
|
||||||
|
]
|
||||||
|
|
||||||
|
class ProcessInfoTest:
|
||||||
|
extends RefCounted
|
||||||
|
var user: int
|
||||||
|
var pid: int
|
||||||
|
var ppid: int
|
||||||
|
var executable: String
|
||||||
|
|
||||||
|
func _init(_user: String, _pid: String, _ppid: String, name: String) -> void:
|
||||||
|
user = _user.to_int()
|
||||||
|
pid = _pid.to_int()
|
||||||
|
ppid = _ppid.to_int()
|
||||||
|
executable = name
|
||||||
|
|
||||||
|
func _to_string() -> String:
|
||||||
|
return "<ProcessInfo: pid:%d, ppid:%d, user:%d, exec:%s>" % [pid, ppid, user, executable]
|
||||||
|
|
||||||
|
func is_running() -> bool:
|
||||||
|
return OS.is_process_running(pid)
|
||||||
|
|
||||||
|
func kill() -> Error:
|
||||||
|
return OS.kill(pid)
|
||||||
|
|
||||||
|
func kill_parent() -> Error:
|
||||||
|
return OS.kill(ppid)
|
||||||
|
|
||||||
|
class ProcessTreeTest:
|
||||||
|
extends RefCounted
|
||||||
|
var processes: Array[ProcessInfoTest] = []
|
||||||
|
|
||||||
|
func _init() -> void:
|
||||||
|
refresh()
|
||||||
|
|
||||||
|
func refresh() -> void:
|
||||||
|
processes.clear()
|
||||||
|
var output := []
|
||||||
|
OS.execute("/usr/bin/ps", ["-eo", "uid,pid,ppid,exe"], output)
|
||||||
|
var lines: PackedStringArray = output[0].split("\n")
|
||||||
|
for line in lines:
|
||||||
|
var parts = line.split(" ",false,4)
|
||||||
|
if parts[0] == "UID":
|
||||||
|
continue
|
||||||
|
if parts[3] == "-":
|
||||||
|
continue
|
||||||
|
var proc: ProcessInfoTest = ProcessInfoTest.new(parts[0],parts[1],parts[2],parts[3])
|
||||||
|
processes.append(proc)
|
||||||
|
|
||||||
|
func has_process_id(id: int) -> bool:
|
||||||
|
return processes.any(func(x: ProcessInfoTest): return x.pid == id)
|
||||||
|
|
||||||
|
func has_process_name(name: String) -> bool:
|
||||||
|
return processes.any(func(x: ProcessInfoTest): return x.executable == name or name in x.executable)
|
||||||
|
|
||||||
|
func get_process(id: int) -> ProcessInfoTest:
|
||||||
|
for proc: ProcessInfoTest in processes:
|
||||||
|
if proc.pid == id:
|
||||||
|
return proc
|
||||||
|
return null
|
||||||
|
|
||||||
|
func get_process_by_name(name: String) -> ProcessInfoTest:
|
||||||
|
for proc: ProcessInfoTest in processes:
|
||||||
|
if proc.executable == name or name in proc.executable:
|
||||||
|
return proc
|
||||||
|
return null
|
||||||
|
|
||||||
|
func get_all_processes_by_name(name: String) -> Array[ProcessInfoTest]:
|
||||||
|
var procs: Array[ProcessInfoTest] = []
|
||||||
|
for proc: ProcessInfoTest in processes:
|
||||||
|
if proc.executable == name or name in proc.executable:
|
||||||
|
procs.append(proc)
|
||||||
|
return procs
|
||||||
|
|
||||||
|
# Called when the script is executed (using File -> Run in Script Editor).
|
||||||
|
func _run() -> void:
|
||||||
|
var tree := ProcessTreeTest.new()
|
||||||
|
for name in finds:
|
||||||
|
var has_proc := tree.has_process_name(name)
|
||||||
|
var proc := tree.get_process_by_name(name)
|
||||||
|
var procs := tree.get_all_processes_by_name(name)
|
||||||
|
print("Has Process '%s': %s" % [name, has_proc])
|
||||||
|
print("First Process '%s': %s" % [name, proc])
|
||||||
|
print("Processes '%s': %s" % [name, procs])
|
||||||
|
print("")
|
||||||
1
tools/pt_testing.gd.uid
Normal file
1
tools/pt_testing.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://b6xjdxwi4o27f
|
||||||
Loading…
Add table
Add a link
Reference in a new issue