diff --git a/.idea/.idea.your are an ai ceo/.idea/libraries/GdSdk.xml b/.idea/.idea.your are an ai ceo/.idea/libraries/GdSdk.xml
index 0059883..04a2e8b 100644
--- a/.idea/.idea.your are an ai ceo/.idea/libraries/GdSdk.xml
+++ b/.idea/.idea.your are an ai ceo/.idea/libraries/GdSdk.xml
@@ -3,7 +3,7 @@
-
+
\ No newline at end of file
diff --git a/Company.cs b/Company.cs
new file mode 100644
index 0000000..36f4c7d
--- /dev/null
+++ b/Company.cs
@@ -0,0 +1,27 @@
+using Godot;
+
+[GlobalClass]
+public partial class Company : Resource
+{
+ [Export]
+ public float Hype { get; set; }
+
+ [Export]
+ public float Money { get; set; } = 10_000;
+
+ [Export]
+ public float Workers { get; set; } = 1;
+
+ [Export]
+ public float AverageSalary { get; set; } = 100;
+
+ ///
+ /// Cost per Quarter
+ ///
+ public float Cost => Workers * AverageSalary;
+
+ ///
+ /// Runway in Quarters
+ ///
+ public int Runway => Mathf.FloorToInt(Money / Cost);
+}
diff --git a/Company.cs.uid b/Company.cs.uid
new file mode 100644
index 0000000..1517d2f
--- /dev/null
+++ b/Company.cs.uid
@@ -0,0 +1 @@
+uid://cxr0qf8ut8t4p
diff --git a/CurrentTimeLine.cs b/CurrentTimeLine.cs
new file mode 100644
index 0000000..dc38f24
--- /dev/null
+++ b/CurrentTimeLine.cs
@@ -0,0 +1,16 @@
+using Godot;
+using yourareanaiceo;
+
+public partial class CurrentTimeLine : Panel
+{
+ [Export]
+ float speed = 2f;
+
+ public override void _Process(double delta)
+ {
+ var pos = OffsetTransformPosition;
+ pos.Y += speed * delta.toFloat();
+
+ OffsetTransformPosition = pos;
+ }
+}
diff --git a/CurrentTimeLine.cs.uid b/CurrentTimeLine.cs.uid
new file mode 100644
index 0000000..3e0936e
--- /dev/null
+++ b/CurrentTimeLine.cs.uid
@@ -0,0 +1 @@
+uid://cbbrups0mkp17
diff --git a/DaySchedule.cs b/DaySchedule.cs
new file mode 100644
index 0000000..d18c4c8
--- /dev/null
+++ b/DaySchedule.cs
@@ -0,0 +1,24 @@
+using System.Linq;
+using Godot;
+
+[SceneTree]
+public partial class DaySchedule : PanelContainer
+{
+ [Export]
+ private Company _company;
+
+ [Export]
+ private int _hoursInDay = 6;
+
+ public override void _Ready()
+ {
+ TimeSlotContainer.GetChildren().ToList().ForEach(child => child.QueueFree());
+
+ for (var i = 0; i < _hoursInDay; i++)
+ {
+ var timeSlot = Instantiator.Instantiate();
+
+ TimeSlotContainer.AddChild(timeSlot);
+ }
+ }
+}
diff --git a/DaySchedule.cs.uid b/DaySchedule.cs.uid
new file mode 100644
index 0000000..4547284
--- /dev/null
+++ b/DaySchedule.cs.uid
@@ -0,0 +1 @@
+uid://xv51uvc4koyc
diff --git a/DaySchedule.tscn b/DaySchedule.tscn
new file mode 100644
index 0000000..b2f56a9
--- /dev/null
+++ b/DaySchedule.tscn
@@ -0,0 +1,93 @@
+[gd_scene format=3 uid="uid://covomnw8s7k1n"]
+
+[ext_resource type="Script" uid="uid://xv51uvc4koyc" path="res://DaySchedule.cs" id="1_b6clr"]
+[ext_resource type="PackedScene" uid="uid://nnr6u0igggve" path="res://TimeSlot.tscn" id="2_ascl5"]
+[ext_resource type="Script" uid="uid://cxr0qf8ut8t4p" path="res://Company.cs" id="2_dtij7"]
+[ext_resource type="Script" uid="uid://cbbrups0mkp17" path="res://CurrentTimeLine.cs" id="3_dtij7"]
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_cm0pq"]
+bg_color = Color(0, 0, 0, 1)
+border_width_left = 4
+border_width_top = 4
+border_width_right = 4
+border_width_bottom = 4
+border_color = Color(0, 0, 0, 1)
+corner_radius_top_left = 4
+corner_radius_top_right = 4
+corner_radius_bottom_right = 4
+corner_radius_bottom_left = 4
+
+[sub_resource type="Resource" id="Resource_b6clr"]
+script = ExtResource("2_dtij7")
+metadata/_custom_type_script = "uid://cxr0qf8ut8t4p"
+
+[sub_resource type="StyleBoxLine" id="StyleBoxLine_r0du0"]
+color = Color(1, 0, 0, 1)
+thickness = 5
+
+[node name="DaySchedule" type="PanelContainer" unique_id=457829015]
+anchors_preset = 8
+anchor_left = 0.5
+anchor_top = 0.5
+anchor_right = 0.5
+anchor_bottom = 0.5
+offset_left = -107.0
+offset_top = -227.0
+offset_right = 107.0
+offset_bottom = 227.0
+grow_horizontal = 2
+grow_vertical = 2
+mouse_filter = 2
+theme_override_styles/panel = SubResource("StyleBoxFlat_cm0pq")
+script = ExtResource("1_b6clr")
+_company = SubResource("Resource_b6clr")
+
+[node name="TimeSlotContainer" type="VBoxContainer" parent="." unique_id=1932322928]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_vertical = 0
+mouse_filter = 2
+theme_override_constants/separation = 2
+alignment = 1
+
+[node name="TimeSlot" parent="TimeSlotContainer" unique_id=979842204 instance=ExtResource("2_ascl5")]
+layout_mode = 2
+
+[node name="TimeSlot2" parent="TimeSlotContainer" unique_id=2109237451 instance=ExtResource("2_ascl5")]
+layout_mode = 2
+
+[node name="TimeSlot3" parent="TimeSlotContainer" unique_id=819921714 instance=ExtResource("2_ascl5")]
+layout_mode = 2
+
+[node name="TimeSlot4" parent="TimeSlotContainer" unique_id=1554222465 instance=ExtResource("2_ascl5")]
+layout_mode = 2
+
+[node name="TimeSlot5" parent="TimeSlotContainer" unique_id=1612666058 instance=ExtResource("2_ascl5")]
+layout_mode = 2
+
+[node name="TimeSlot6" parent="TimeSlotContainer" unique_id=1912431362 instance=ExtResource("2_ascl5")]
+layout_mode = 2
+
+[node name="TimeSlot7" parent="TimeSlotContainer" unique_id=1182001581 instance=ExtResource("2_ascl5")]
+layout_mode = 2
+
+[node name="TimeSlot8" parent="TimeSlotContainer" unique_id=193012813 instance=ExtResource("2_ascl5")]
+layout_mode = 2
+
+[node name="TimeSlot9" parent="TimeSlotContainer" unique_id=886153912 instance=ExtResource("2_ascl5")]
+visible = false
+layout_mode = 2
+
+[node name="TimeSlot10" parent="TimeSlotContainer" unique_id=1760034209 instance=ExtResource("2_ascl5")]
+visible = false
+layout_mode = 2
+
+[node name="CurrentTimeLine" type="Panel" parent="." unique_id=961292687]
+custom_minimum_size = Vector2(0, 5)
+clip_contents = true
+layout_mode = 2
+size_flags_vertical = 0
+offset_transform_enabled = true
+mouse_filter = 2
+theme_override_styles/panel = SubResource("StyleBoxLine_r0du0")
+script = ExtResource("3_dtij7")
diff --git a/DoubleExtensions.cs b/DoubleExtensions.cs
new file mode 100644
index 0000000..d8322c3
--- /dev/null
+++ b/DoubleExtensions.cs
@@ -0,0 +1,9 @@
+namespace yourareanaiceo;
+
+public static class DoubleExtensions
+{
+ public static float toFloat(this double value)
+ {
+ return (float)value;
+ }
+}
diff --git a/DoubleExtensions.cs.uid b/DoubleExtensions.cs.uid
new file mode 100644
index 0000000..fd843cf
--- /dev/null
+++ b/DoubleExtensions.cs.uid
@@ -0,0 +1 @@
+uid://dtfiuvcat531i
diff --git a/DropZone.cs b/DropZone.cs
new file mode 100644
index 0000000..3dd1b40
--- /dev/null
+++ b/DropZone.cs
@@ -0,0 +1,32 @@
+using Godot;
+
+public partial class DropZone : Control
+{
+ public override bool _CanDropData(Vector2 atPosition, Variant data)
+ {
+ return data.VariantType == Variant.Type.Object
+ && data.AsGodotObject() is MeetingControlDragData;
+ }
+
+ public override void _DropData(Vector2 atPosition, Variant data)
+ {
+ var meetingControl = ((MeetingControlDragData)data).MeetingControl;
+ var meetingPhysicsBox = meetingControl.MeetingPhysicsBox;
+
+ var main = (Main)FindParent("Main");
+ main.AddChild(meetingPhysicsBox);
+ meetingPhysicsBox.Position = GetGlobalMousePosition();
+ meetingControl.QueueFree();
+
+ meetingControl.DragIsHandled = true;
+ }
+
+ public override void _Notification(int what)
+ {
+ if (what == NotificationDragBegin)
+ MouseFilter = MouseFilterEnum.Pass;
+
+ if (what == NotificationDragEnd)
+ MouseFilter = MouseFilterEnum.Ignore;
+ }
+}
diff --git a/DropZone.cs.uid b/DropZone.cs.uid
new file mode 100644
index 0000000..f09a86b
--- /dev/null
+++ b/DropZone.cs.uid
@@ -0,0 +1 @@
+uid://bs531c76ivhtf
diff --git a/Main.cs b/Main.cs
new file mode 100644
index 0000000..d240ec2
--- /dev/null
+++ b/Main.cs
@@ -0,0 +1,4 @@
+using Godot;
+
+[SceneTree]
+public partial class Main : Node2D { }
diff --git a/Main.cs.uid b/Main.cs.uid
new file mode 100644
index 0000000..c0a3756
--- /dev/null
+++ b/Main.cs.uid
@@ -0,0 +1 @@
+uid://d1h0qvskvk1wu
diff --git a/Main.tscn b/Main.tscn
index bc2d0ee..d440a39 100644
--- a/Main.tscn
+++ b/Main.tscn
@@ -1,8 +1,12 @@
[gd_scene format=3 uid="uid://b2rl7r8oav3hy"]
+[ext_resource type="Script" uid="uid://d1h0qvskvk1wu" path="res://Main.cs" id="1_3dxm6"]
[ext_resource type="PackedScene" uid="uid://dciugg77wsy6p" path="res://MeetingPhysicsBox.tscn" id="1_glv2v"]
-[ext_resource type="PackedScene" uid="uid://nnr6u0igggve" path="res://TimeSlot.tscn" id="1_uu6xs"]
+[ext_resource type="PackedScene" uid="uid://covomnw8s7k1n" path="res://DaySchedule.tscn" id="1_r0du0"]
[ext_resource type="Resource" uid="uid://mifwco1yj8kc" path="res://resources/meetings/coffee_meeting.tres" id="3_r0du0"]
+[ext_resource type="Resource" uid="uid://du72uxjqr0h4a" path="res://resources/meetings/lockin.tres" id="4_cm0pq"]
+[ext_resource type="Resource" uid="uid://bcd4qf4i84pwf" path="res://resources/meetings/work_product_1.tres" id="5_fos0i"]
+[ext_resource type="Script" uid="uid://bs531c76ivhtf" path="res://DropZone.cs" id="7_lgr22"]
[sub_resource type="LabelSettings" id="LabelSettings_sko1m"]
font_size = 64
@@ -12,8 +16,6 @@ stacked_outline_0/size = 9
stacked_shadow_0/offset = Vector2(4, 4)
stacked_shadow_0/outline_size = 2
-[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_50jir"]
-
[sub_resource type="RectangleShape2D" id="RectangleShape2D_sko1m"]
size = Vector2(727.5, 20)
@@ -21,6 +23,12 @@ size = Vector2(727.5, 20)
size = Vector2(21.5, 1920)
[node name="Main" type="Node2D" unique_id=287617203]
+script = ExtResource("1_3dxm6")
+
+[node name="MeetingSpawn" type="Marker2D" parent="." unique_id=1266113438]
+unique_name_in_owner = true
+position = Vector2(775, 36)
+gizmo_extents = 40.0
[node name="CanvasLayer" type="CanvasLayer" parent="." unique_id=1328071901]
@@ -53,57 +61,75 @@ grow_horizontal = 0
text = "Inbox"
label_settings = SubResource("LabelSettings_sko1m")
-[node name="PanelContainer" type="PanelContainer" parent="." unique_id=1636973054]
-anchors_preset = 8
-anchor_left = 0.5
-anchor_top = 0.5
-anchor_right = 0.5
-anchor_bottom = 0.5
-offset_left = 96.0
-offset_top = 114.0
-offset_right = 302.0
-offset_bottom = 574.0
-grow_horizontal = 2
-grow_vertical = 2
-mouse_filter = 2
-theme_override_styles/panel = SubResource("StyleBoxEmpty_50jir")
+[node name="PanelContainer" type="FoldableContainer" parent="CanvasLayer/Control" unique_id=1121461524]
+layout_mode = 1
+anchors_preset = 1
+anchor_left = 1.0
+anchor_right = 1.0
+offset_left = -245.0
+offset_right = 4.535034
+offset_bottom = 149.0
+grow_horizontal = 0
+title = "Your Company Inc."
+title_alignment = 1
-[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer" unique_id=1658498861]
-layout_mode = 2
-mouse_filter = 2
-alignment = 1
-
-[node name="TimeSlot" parent="PanelContainer/VBoxContainer" unique_id=979842204 instance=ExtResource("1_uu6xs")]
+[node name="VBoxContainer" type="VBoxContainer" parent="CanvasLayer/Control/PanelContainer" unique_id=1331001176]
layout_mode = 2
-[node name="TimeSlot2" parent="PanelContainer/VBoxContainer" unique_id=1532657435 instance=ExtResource("1_uu6xs")]
+[node name="HBoxContainer4" type="HBoxContainer" parent="CanvasLayer/Control/PanelContainer/VBoxContainer" unique_id=879116080]
+modulate = Color(1, 0, 0, 1)
layout_mode = 2
-[node name="TimeSlot3" parent="PanelContainer/VBoxContainer" unique_id=1504478834 instance=ExtResource("1_uu6xs")]
+[node name="Label" type="Label" parent="CanvasLayer/Control/PanelContainer/VBoxContainer/HBoxContainer4" unique_id=54936711]
+layout_mode = 2
+size_flags_horizontal = 3
+text = "Runway"
+
+[node name="Label2" type="Label" parent="CanvasLayer/Control/PanelContainer/VBoxContainer/HBoxContainer4" unique_id=111473790]
+layout_mode = 2
+text = "2"
+
+[node name="HBoxContainer" type="HBoxContainer" parent="CanvasLayer/Control/PanelContainer/VBoxContainer" unique_id=500602395]
layout_mode = 2
-[node name="TimeSlot4" parent="PanelContainer/VBoxContainer" unique_id=1891572413 instance=ExtResource("1_uu6xs")]
+[node name="Label" type="Label" parent="CanvasLayer/Control/PanelContainer/VBoxContainer/HBoxContainer" unique_id=1599952499]
+layout_mode = 2
+size_flags_horizontal = 3
+text = "Hype"
+
+[node name="Label2" type="Label" parent="CanvasLayer/Control/PanelContainer/VBoxContainer/HBoxContainer" unique_id=780587971]
+layout_mode = 2
+text = "10"
+
+[node name="HBoxContainer2" type="HBoxContainer" parent="CanvasLayer/Control/PanelContainer/VBoxContainer" unique_id=981225226]
layout_mode = 2
-[node name="TimeSlot5" parent="PanelContainer/VBoxContainer" unique_id=464659559 instance=ExtResource("1_uu6xs")]
+[node name="Label" type="Label" parent="CanvasLayer/Control/PanelContainer/VBoxContainer/HBoxContainer2" unique_id=1687312201]
+layout_mode = 2
+size_flags_horizontal = 3
+text = "Money"
+
+[node name="Label2" type="Label" parent="CanvasLayer/Control/PanelContainer/VBoxContainer/HBoxContainer2" unique_id=172841693]
+layout_mode = 2
+text = "10.000"
+
+[node name="HBoxContainer3" type="HBoxContainer" parent="CanvasLayer/Control/PanelContainer/VBoxContainer" unique_id=2146415473]
layout_mode = 2
-[node name="TimeSlot6" parent="PanelContainer/VBoxContainer" unique_id=1773919778 instance=ExtResource("1_uu6xs")]
+[node name="Label" type="Label" parent="CanvasLayer/Control/PanelContainer/VBoxContainer/HBoxContainer3" unique_id=1336632204]
layout_mode = 2
+size_flags_horizontal = 3
+text = "Workers"
-[node name="TimeSlot7" parent="PanelContainer/VBoxContainer" unique_id=1476334804 instance=ExtResource("1_uu6xs")]
+[node name="Label2" type="Label" parent="CanvasLayer/Control/PanelContainer/VBoxContainer/HBoxContainer3" unique_id=617177241]
layout_mode = 2
+text = "1"
-[node name="TimeSlot8" parent="PanelContainer/VBoxContainer" unique_id=2116243857 instance=ExtResource("1_uu6xs")]
-layout_mode = 2
-
-[node name="TimeSlot9" parent="PanelContainer/VBoxContainer" unique_id=1672825401 instance=ExtResource("1_uu6xs")]
-visible = false
-layout_mode = 2
-
-[node name="TimeSlot10" parent="PanelContainer/VBoxContainer" unique_id=488121571 instance=ExtResource("1_uu6xs")]
-visible = false
-layout_mode = 2
+[node name="DaySchedule" parent="." unique_id=457829015 instance=ExtResource("1_r0du0")]
+offset_left = 106.0
+offset_top = 117.0
+offset_right = 320.0
+offset_bottom = 571.0
[node name="Box" type="StaticBody2D" parent="." unique_id=56956355]
@@ -130,10 +156,12 @@ MeetingResource = ExtResource("3_r0du0")
[node name="Meeting4" parent="." unique_id=1960552374 instance=ExtResource("1_glv2v")]
position = Vector2(707, -340)
rotation = 0.24779713
+MeetingResource = ExtResource("4_cm0pq")
[node name="Meeting5" parent="." unique_id=1692042144 instance=ExtResource("1_glv2v")]
position = Vector2(851, -500)
rotation = 0.24779713
+MeetingResource = ExtResource("5_fos0i")
[node name="Meeting6" parent="." unique_id=2120697586 instance=ExtResource("1_glv2v")]
position = Vector2(604, -619.99994)
@@ -152,6 +180,7 @@ rotation = 0.24779713
[node name="Meeting9" parent="." unique_id=1055632102 instance=ExtResource("1_glv2v")]
position = Vector2(614, -732.99994)
rotation = 0.24779713
+MeetingResource = ExtResource("5_fos0i")
[node name="Meeting2" parent="." unique_id=1691479453 instance=ExtResource("1_glv2v")]
position = Vector2(937, -352)
@@ -162,3 +191,13 @@ MeetingResource = ExtResource("3_r0du0")
position = Vector2(762.9999, -181.00012)
rotation = -0.18364333
MeetingResource = ExtResource("3_r0du0")
+
+[node name="DropZone" type="Control" parent="." unique_id=80494692]
+layout_mode = 3
+anchors_preset = 0
+offset_left = 457.0
+offset_top = 9.0
+offset_right = 1080.0
+offset_bottom = 571.0
+mouse_filter = 2
+script = ExtResource("7_lgr22")
diff --git a/MeetingControl.cs b/MeetingControl.cs
index 8582fa5..7997d56 100644
--- a/MeetingControl.cs
+++ b/MeetingControl.cs
@@ -11,7 +11,11 @@ public partial class MeetingControl : Control
[Export]
public MeetingPhysicsBox MeetingPhysicsBox;
- public bool InSlot { get; set; }
+ private MeetingControl otherMeetingControl;
+
+ public bool DragIsHandled { get; set; }
+
+ public bool ForceDragged { get; set; }
public override void _Ready()
{
@@ -25,34 +29,69 @@ public partial class MeetingControl : Control
SetDragPreview(preview);
Visible = false;
- InSlot = false;
+ DragIsHandled = false;
+ ForceDragged = false;
return Variant.From(new MeetingControlDragData(this));
}
+ public override bool _CanDropData(Vector2 atPosition, Variant data)
+ {
+ return data.VariantType == Variant.Type.Object
+ && data.AsGodotObject() is MeetingControlDragData;
+ }
+
+ public override void _DropData(Vector2 atPosition, Variant data)
+ {
+ var meetingData = (MeetingControlDragData)data;
+
+ otherMeetingControl = meetingData.MeetingControl;
+ var otherParent = otherMeetingControl.GetParent();
+
+ otherMeetingControl.Reparent(GetParent(), false);
+ Reparent(otherParent, false);
+
+ otherMeetingControl.Visible = true;
+ otherMeetingControl.DragIsHandled = true;
+
+ if (otherMeetingControl.ForceDragged)
+ {
+ RespawnPhysicsBoxFromSpawn();
+ otherMeetingControl.ForceDragged = false;
+ }
+ }
+
public void StartDrag()
{
var preview = CreatePreview();
var data = Variant.From(new MeetingControlDragData(this));
ForceDrag(data, preview);
+
+ DragIsHandled = false;
+ ForceDragged = true;
}
public override void _Notification(int what)
{
+ // Notfall respawn
if (what == NotificationDragEnd)
{
- if (InSlot)
- {
+ if (DragIsHandled)
return;
- }
- FindParent("Main").AddChild(MeetingPhysicsBox);
- MeetingPhysicsBox.Position = GetGlobalMousePosition();
- QueueFree();
+ RespawnPhysicsBoxFromSpawn();
}
}
+ private void RespawnPhysicsBoxFromSpawn()
+ {
+ var main = (Main)FindParent("Main");
+ main.AddChild(MeetingPhysicsBox);
+ MeetingPhysicsBox.Position = main.MeetingSpawn.GlobalPosition;
+ QueueFree();
+ }
+
private Control CreatePreview()
{
var copy = Duplicate() as MeetingControl;
diff --git a/MeetingControl.tscn b/MeetingControl.tscn
index dcaf095..41d53f5 100644
--- a/MeetingControl.tscn
+++ b/MeetingControl.tscn
@@ -5,13 +5,31 @@
[node name="MeetingControl" type="Control" unique_id=778678487]
layout_mode = 3
-anchors_preset = 0
-offset_right = 206.0
-offset_bottom = 54.0
+anchors_preset = 8
+anchor_left = 0.5
+anchor_top = 0.5
+anchor_right = 0.5
+anchor_bottom = 0.5
+offset_left = -103.0
+offset_top = -27.0
+offset_right = 103.0
+offset_bottom = 27.0
+grow_horizontal = 2
+grow_vertical = 2
script = ExtResource("1_o5h3n")
[node name="MeetingControlGfx" parent="." unique_id=1923695250 instance=ExtResource("1_o8u20")]
unique_name_in_owner = true
-layout_mode = 0
-offset_right = 206.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 = -103.0
+offset_top = -27.0
+offset_right = 103.0
+offset_bottom = 27.0
+grow_horizontal = 2
+grow_vertical = 2
mouse_filter = 2
diff --git a/MeetingControlGfx.tscn b/MeetingControlGfx.tscn
index ccdc5a9..3874270 100644
--- a/MeetingControlGfx.tscn
+++ b/MeetingControlGfx.tscn
@@ -3,6 +3,9 @@
[ext_resource type="Script" uid="uid://cxbjuwkso3fro" path="res://MeetingControlGfx.cs" id="1_ad8oc"]
[ext_resource type="Texture2D" uid="uid://dyxftkkuf7h7w" path="res://icon.svg" id="1_vkyb6"]
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ad8oc"]
+bg_color = Color(0.20152655, 0.20152661, 0.20152646, 1)
+
[sub_resource type="LabelSettings" id="LabelSettings_vkyb6"]
line_spacing = -4.0
font_size = 12
@@ -11,6 +14,7 @@ font_size = 12
offset_right = 250.0
offset_bottom = 54.0
size_flags_horizontal = 3
+theme_override_styles/panel = SubResource("StyleBoxFlat_ad8oc")
script = ExtResource("1_ad8oc")
[node name="MarginContainer" type="MarginContainer" parent="." unique_id=2076398338]
diff --git a/MeetingPhysicsBox.cs b/MeetingPhysicsBox.cs
index db769af..5277245 100644
--- a/MeetingPhysicsBox.cs
+++ b/MeetingPhysicsBox.cs
@@ -3,12 +3,13 @@ using Godot;
[SceneTree]
public partial class MeetingPhysicsBox : RigidBody2D
{
- [Export]
- public MeetingResource MeetingResource { get; set; } = new DummyMeetingResource();
+ private Vector2 _dragTarget;
+ private bool _isDragging;
private bool _mouseInside;
- private bool _isDragging;
- private Vector2 _dragTarget;
+
+ [Export]
+ public MeetingResource MeetingResource { get; set; } = new DummyMeetingResource();
public override void _Ready()
{
@@ -34,16 +35,12 @@ public partial class MeetingPhysicsBox : RigidBody2D
using (@event)
{
if (@event is InputEventMouse mouseEvent)
- {
if (_mouseInside)
- {
if (mouseEvent.IsPressed() && mouseEvent.ButtonMask == MouseButtonMask.Left)
{
GD.Print("Start Dragging");
StartDragging();
}
- }
- }
}
}
@@ -80,5 +77,6 @@ public partial class MeetingPhysicsBox : RigidBody2D
meetingControl.Position = new Vector2(-5000, -5000);
GetParent().RemoveChild(this);
+ _mouseInside = false;
}
}
diff --git a/TimeSlot.cs b/TimeSlot.cs
index f8beec8..499a376 100644
--- a/TimeSlot.cs
+++ b/TimeSlot.cs
@@ -1,12 +1,12 @@
using Godot;
+[SceneTree]
public partial class TimeSlot : PanelContainer
{
public MeetingControl MeetingControl { get; set; }
public override bool _CanDropData(Vector2 atPosition, Variant data)
{
- GD.Print("DRAGGED OVERR!!!");
return data.VariantType == Variant.Type.Object
&& data.AsGodotObject() is MeetingControlDragData;
}
@@ -16,21 +16,18 @@ public partial class TimeSlot : PanelContainer
var meetingData = (MeetingControlDragData)data;
MeetingControl = meetingData.MeetingControl;
- meetingData.MeetingControl.InSlot = true;
MeetingControl.Reparent(this, false);
MeetingControl.Visible = true;
+
+ meetingData.MeetingControl.DragIsHandled = true;
}
public override void _Notification(int what)
{
if (what == NotificationDragBegin)
- {
MouseFilter = MouseFilterEnum.Pass;
- }
if (what == NotificationDragEnd)
- {
MouseFilter = MouseFilterEnum.Ignore;
- }
}
}
diff --git a/TimeSlot.tscn b/TimeSlot.tscn
index 06282ee..45826fa 100644
--- a/TimeSlot.tscn
+++ b/TimeSlot.tscn
@@ -2,9 +2,14 @@
[ext_resource type="Script" uid="uid://dldaxqajhnnva" path="res://TimeSlot.cs" id="1_50jir"]
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_cm0pq"]
+bg_color = Color(0.39060682, 0.37537947, 0.313594, 1)
+border_color = Color(0, 0, 0, 0.16078432)
+
[node name="TimeSlot" type="PanelContainer" unique_id=979842204]
custom_minimum_size = Vector2(206, 54)
offset_right = 206.0
offset_bottom = 54.0
mouse_filter = 2
+theme_override_styles/panel = SubResource("StyleBoxFlat_cm0pq")
script = ExtResource("1_50jir")
diff --git a/addons/rider-plugin/CONTRIBUTING.md b/addons/rider-plugin/CONTRIBUTING.md
new file mode 100644
index 0000000..45f104b
--- /dev/null
+++ b/addons/rider-plugin/CONTRIBUTING.md
@@ -0,0 +1,33 @@
+# Contribution
+
+Hello, thanks for taking time and helping out with the addon!
+
+Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. Please sign the CLA before sending the PR: https://www.jetbrains.com/agreements/cla/.
+
+#### Local setup
+
+Open the `godot-editor-addon/CMakeLists.txt` in Rider 2026.1+, select `rider-gdextension` target in the run configuration selector.
+There are some more fixes coming in 2026.2, which will allow working on gdscript and cpp files within the same workspace.
+
+#### Signing the binaries
+
+Plugin binaries need to be signed to comply with modern operating system security requirements. Unsigned dynamic libraries may fail to load or trigger security warnings:
+
+- **macOS**: Requires code signing (and often notarization) for `.dylib` files. Unsigned libraries may simply fail to load.
+- **Windows**: SmartScreen may block unsigned binaries, and corporate environments often enforce signed code only.
+- **Linux**: Generally allows unsigned `.so` files, but some sandboxed environments (Flatpak, Snap) impose restrictions.
+
+**How signing is implemented:**
+
+1. **TeamCity Configuration**: [ijplatform_master_Net_Deploy_Plugins_Public_Godot](https://buildserver.labs.intellij.net/buildConfiguration/ijplatform_master_Net_Deploy_Plugins_Public_Godot) (internal JetBrains link)
+ - Note: The automatic trigger on new tags is currently not working, so manual triggering is required.
+
+2. **Release Process**:
+ - First, use your GitHub Action to prepare a **pre-release** with a tag
+ - Manually trigger the TeamCity configuration on the necessary branch/tag
+ - The configuration will download assets, sign them, and upload them back (removing the pre-release flag)
+ - The pre-release flag is required at the start; otherwise, the signing configuration will skip the release (protection against double signing)
+
+3. **Signing existing releases**:
+ - You can run signing on already existing old releases/tags
+ - Mark them as pre-release first, then run the configuration on the necessary tag
diff --git a/addons/rider-plugin/LICENCE b/addons/rider-plugin/LICENCE
new file mode 100644
index 0000000..f1f8c07
--- /dev/null
+++ b/addons/rider-plugin/LICENCE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2025 JetBrains
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/addons/rider-plugin/README.md b/addons/rider-plugin/README.md
new file mode 100644
index 0000000..51b6fb3
--- /dev/null
+++ b/addons/rider-plugin/README.md
@@ -0,0 +1,51 @@
+# JetBrains Rider Integration – Godot addon
+
+This addon currently provides two features:
+1. Finds all Rider installations in the system and provides a selector on the `Text Editor` -> `External` tab in the settings to select one.
+2. Provides the "Use Rider" toggle in the Godot toolbar and, when enabled, applies a set of editor settings recommended for working with JetBrains Rider. The goal is to make it trivial to switch between Rider‑optimized settings and stock Godot settings with a single click.
+
+## Quick start
+
+Requirements:
+- Godot 4.5+
+
+Install:
+1. Inside the Godot editor, it can be installed from the AssetLib view or [downloaded](https://godotengine.org/asset-library/asset/4576)
+2. [Optional] Change the initial value of `active` in the plugin.cfg
+3. [Optional] Change the initial values in the presets.json file.
+4. Enable "JetBrains Rider External Editor" plugin in the Project → Project Settings… → Plugins tab.
+
+Use:
+- A toolbar toggle named "Use Rider" will appear. Click it to turn the preset On/Off.
+
+Screenshot:
+
+
+## What the toggle changes
+
+The preset values live in `presets.json`.
+
+When ON:
+- Write the values from the "on" preset into the Editor Settings.
+
+When OFF:
+- Write the values from the "off" preset into the Editor Settings.
+
+Note: The plugin does not currently auto‑set Rider’s executable path or flags. See Plans below.
+
+## Setting Rider to be the external editor
+
+The plugin automatically detects installed Rider versions on your system and provides a convenient dropdown menu to
+select which installation to use as your external editor.
+
+- The plugin scans common installation locations for Rider on Windows, macOS, and Linux.
+- Detected installations appear in the "Select Rider" dropdown in the toolbar.
+- When you select a Rider installation, the plugin automatically updates the `dotnet/editor/external_editor_path` editor
+ setting.
+
+## License
+See `addons/rider-plugin/LICENCE`.
+
+## Acknowledgements
+Created by JetBrains to streamline using Rider with Godot.
+Initial idea https://github.com/sszigeti/toggle_external_editor
diff --git a/addons/rider-plugin/bin/linux/librider-gdextension.linux.editor.arm64.so b/addons/rider-plugin/bin/linux/librider-gdextension.linux.editor.arm64.so
new file mode 100644
index 0000000..17edcec
Binary files /dev/null and b/addons/rider-plugin/bin/linux/librider-gdextension.linux.editor.arm64.so differ
diff --git a/addons/rider-plugin/bin/linux/librider-gdextension.linux.editor.x86_64.so b/addons/rider-plugin/bin/linux/librider-gdextension.linux.editor.x86_64.so
new file mode 100644
index 0000000..7730052
Binary files /dev/null and b/addons/rider-plugin/bin/linux/librider-gdextension.linux.editor.x86_64.so differ
diff --git a/addons/rider-plugin/bin/macos/librider-gdextension.macos.editor.dylib b/addons/rider-plugin/bin/macos/librider-gdextension.macos.editor.dylib
new file mode 100644
index 0000000..604f726
Binary files /dev/null and b/addons/rider-plugin/bin/macos/librider-gdextension.macos.editor.dylib differ
diff --git a/addons/rider-plugin/bin/rider-plugin.gdextension b/addons/rider-plugin/bin/rider-plugin.gdextension
new file mode 100644
index 0000000..57755d8
--- /dev/null
+++ b/addons/rider-plugin/bin/rider-plugin.gdextension
@@ -0,0 +1,16 @@
+[configuration]
+
+entry_symbol = "rider_library_init"
+compatibility_minimum = "4.5.0"
+
+[libraries]
+
+macos.single.debug = "./macos/librider-gdextension.macos.editor.dylib"
+
+windows.arm64.single.debug = "./windows/rider-gdextension.windows.editor.arm64.dll"
+
+windows.x86_64.single.debug = "./windows/rider-gdextension.windows.editor.x86_64.dll"
+
+linux.x86_64.single.debug = "./linux/librider-gdextension.linux.editor.x86_64.so"
+
+linux.arm64.single.debug = "./linux/librider-gdextension.linux.editor.arm64.so"
\ No newline at end of file
diff --git a/addons/rider-plugin/bin/rider-plugin.gdextension.uid b/addons/rider-plugin/bin/rider-plugin.gdextension.uid
new file mode 100644
index 0000000..e69de29
diff --git a/addons/rider-plugin/bin/windows/rider-gdextension.windows.editor.x86_64.dll b/addons/rider-plugin/bin/windows/rider-gdextension.windows.editor.x86_64.dll
new file mode 100644
index 0000000..66397c2
Binary files /dev/null and b/addons/rider-plugin/bin/windows/rider-gdextension.windows.editor.x86_64.dll differ
diff --git a/addons/rider-plugin/bin/windows/~rider-gdextension.windows.editor.x86_64.dll b/addons/rider-plugin/bin/windows/~rider-gdextension.windows.editor.x86_64.dll
new file mode 100644
index 0000000..66397c2
Binary files /dev/null and b/addons/rider-plugin/bin/windows/~rider-gdextension.windows.editor.x86_64.dll differ
diff --git a/addons/rider-plugin/icons/icon.svg b/addons/rider-plugin/icons/icon.svg
new file mode 100644
index 0000000..04cb843
--- /dev/null
+++ b/addons/rider-plugin/icons/icon.svg
@@ -0,0 +1,144 @@
+
+
+
+
diff --git a/addons/rider-plugin/icons/icon.svg.import b/addons/rider-plugin/icons/icon.svg.import
new file mode 100644
index 0000000..05cbbf5
--- /dev/null
+++ b/addons/rider-plugin/icons/icon.svg.import
@@ -0,0 +1,43 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://wrdrj6wednn8"
+path="res://.godot/imported/icon.svg-45c914cff7482ba9564963fe65b548e4.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/rider-plugin/icons/icon.svg"
+dest_files=["res://.godot/imported/icon.svg-45c914cff7482ba9564963fe65b548e4.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/addons/rider-plugin/plugin.cfg b/addons/rider-plugin/plugin.cfg
new file mode 100644
index 0000000..5a4ada1
--- /dev/null
+++ b/addons/rider-plugin/plugin.cfg
@@ -0,0 +1,12 @@
+[plugin]
+
+name="JetBrains Rider External Editor"
+description="Provides a toolbar toggle, to switch a set of settings on and off. Default set of settings helps to enable/disable the following settings recommended by the Rider documentation https://www.jetbrains.com/help/rider/Godot.html#optimize-godot-editor-for-rider"
+author="JetBrains"
+version="v1.3.0"
+script="rider-plugin.gd"
+
+[presets]
+
+active="on"
+presets="presets.json"
diff --git a/addons/rider-plugin/presets.json b/addons/rider-plugin/presets.json
new file mode 100644
index 0000000..5e38bf3
--- /dev/null
+++ b/addons/rider-plugin/presets.json
@@ -0,0 +1,15 @@
+{
+ "on": {
+ "text_editor/external/use_external_editor": true,
+ "interface/editor/import_resources_when_unfocused": true,
+ "interface/editor/save_on_focus_loss": true,
+ "text_editor/behavior/files/auto_reload_scripts_on_external_change": true,
+ "run/window_placement/game_embed_mode": -1
+ },
+ "off": {
+ "text_editor/external/use_external_editor": false,
+ "interface/editor/import_resources_when_unfocused": false,
+ "interface/editor/save_on_focus_loss": false,
+ "text_editor/behavior/files/auto_reload_scripts_on_external_change": false
+ }
+}
diff --git a/addons/rider-plugin/rider-plugin.gd b/addons/rider-plugin/rider-plugin.gd
new file mode 100644
index 0000000..f2587dd
--- /dev/null
+++ b/addons/rider-plugin/rider-plugin.gd
@@ -0,0 +1,78 @@
+@tool
+extends EditorPlugin
+
+var editor_settings: EditorSettings
+var checkbutton: CheckButton
+var _preset_applier: PresetApplier
+var _locator_service: RiderLocatorService
+var _plugin_cfg_path: String
+var _presets_json_path: String
+
+func _enter_tree() -> void:
+ editor_settings = EditorInterface.get_editor_settings()
+ var script_path := (get_script() as Script).resource_path
+ var plugin_dir := script_path.get_base_dir()
+ _plugin_cfg_path = plugin_dir + "/plugin.cfg"
+
+ _write_godot_editor_cfg()
+
+ var cfg := ConfigFile.new()
+ var err := cfg.load(_plugin_cfg_path)
+ if err != OK:
+ push_warning("Failed to load plugin.cfg: %s" % [err])
+ return
+ var active_str := str(cfg.get_value("presets", "active", "on"))
+ var is_active := active_str == "on"
+ var presets_rel_path := str(cfg.get_value("presets", "presets", "presets.json"))
+ _presets_json_path = plugin_dir + "/" + presets_rel_path
+
+ # Build UI
+ checkbutton = CheckButton.new()
+ checkbutton.text = "Use Rider"
+ checkbutton.tooltip_text = "Shortcut for setting recommended settings"
+ checkbutton.button_pressed = is_active
+ checkbutton.pressed.connect(_on_checkbutton_pressed)
+ add_control_to_container(EditorPlugin.CONTAINER_TOOLBAR, checkbutton)
+
+ # Initialize services and panel
+ _locator_service = RiderLocatorService.new()
+ _preset_applier = PresetApplier.new(_presets_json_path)
+
+ _locator_service.start_search()
+
+ # Ensure settings reflect current state on startup
+ _preset_applier.apply_preset(editor_settings, is_active)
+
+func _on_checkbutton_pressed() -> void:
+ var cfg := ConfigFile.new()
+ if cfg.load(_plugin_cfg_path) != OK:
+ push_warning("Failed to load plugin.cfg to update state")
+ return
+ var is_active := checkbutton.button_pressed
+ var key := _preset_applier.get_preset_key(is_active)
+ cfg.set_value("presets", "active", key)
+ var save_err := cfg.save(_plugin_cfg_path)
+ if save_err != OK:
+ push_warning("Failed to save plugin.cfg: %s" % [save_err])
+ # Apply selected preset to editor settings
+ _preset_applier.apply_preset(editor_settings, is_active)
+
+func _exit_tree() -> void:
+ EditorSettingsUtil.erase_rider_external_editor_setting()
+ if checkbutton != null:
+ remove_control_from_container(EditorPlugin.CONTAINER_TOOLBAR, checkbutton)
+ checkbutton.queue_free()
+
+ var args := OS.get_cmdline_args()
+ if "--rider-addon-tests" in args:
+ print("==== rider-addon-tests finished ====")
+
+func _write_godot_editor_cfg() -> void:
+ var settings_dir := EditorInterface.get_editor_paths().get_project_settings_dir()
+ var cfg_path := settings_dir.path_join("rider_addon_godot_editor.cfg")
+ var cfg := ConfigFile.new()
+ cfg.set_value("editor_metadata", "process_id", OS.get_process_id())
+ cfg.set_value("editor_metadata", "executable_path", OS.get_executable_path())
+ var err := cfg.save(cfg_path)
+ if err != OK:
+ push_warning("Failed to save rider_addon_godot_editor.cfg: %s" % [err])
diff --git a/addons/rider-plugin/rider-plugin.gd.uid b/addons/rider-plugin/rider-plugin.gd.uid
new file mode 100644
index 0000000..80edc2b
--- /dev/null
+++ b/addons/rider-plugin/rider-plugin.gd.uid
@@ -0,0 +1 @@
+uid://c1x58xm2w1n20
diff --git a/addons/rider-plugin/screenshots/Toolbar.png b/addons/rider-plugin/screenshots/Toolbar.png
new file mode 100644
index 0000000..51c2617
Binary files /dev/null and b/addons/rider-plugin/screenshots/Toolbar.png differ
diff --git a/addons/rider-plugin/screenshots/Toolbar.png.import b/addons/rider-plugin/screenshots/Toolbar.png.import
new file mode 100644
index 0000000..94f74e7
--- /dev/null
+++ b/addons/rider-plugin/screenshots/Toolbar.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ci3pvmb68i8lh"
+path="res://.godot/imported/Toolbar.png-a521e2493bd3c08a829245b3129bb58f.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/rider-plugin/screenshots/Toolbar.png"
+dest_files=["res://.godot/imported/Toolbar.png-a521e2493bd3c08a829245b3129bb58f.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/addons/rider-plugin/scripts/editor_settings_util.gd b/addons/rider-plugin/scripts/editor_settings_util.gd
new file mode 100644
index 0000000..0af18fb
--- /dev/null
+++ b/addons/rider-plugin/scripts/editor_settings_util.gd
@@ -0,0 +1,66 @@
+@tool
+class_name EditorSettingsUtil
+
+# this is rider own setting, not a part of Godot settings
+const EXTERNAL_EDITOR_SETTING: String = "text_editor/external/editor"
+# this is Godot setting
+const EXEC_PATH_SETTING: String = "text_editor/external/exec_path"
+
+
+static func set_external_editor_path(path: String) -> void:
+ var editor_settings := EditorInterface.get_editor_settings()
+ editor_settings.set_setting(EXEC_PATH_SETTING, path)
+
+static func get_external_editor_path() -> String:
+ var editor_settings := EditorInterface.get_editor_settings()
+ if editor_settings.has_setting(EXEC_PATH_SETTING):
+ return editor_settings.get_setting(EXEC_PATH_SETTING)
+ else:
+ return ""
+
+# Returns the current dropdown index, 0 if the setting doesn't exist.
+static func get_rider_selector_index() -> int:
+ var editor_settings := EditorInterface.get_editor_settings()
+ if not editor_settings.has_setting(EXTERNAL_EDITOR_SETTING):
+ return 0
+ return editor_settings.get_setting(EXTERNAL_EDITOR_SETTING)
+
+static func erase_rider_external_editor_setting() -> void:
+ var editor_settings := EditorInterface.get_editor_settings()
+ if editor_settings.has_setting(EXTERNAL_EDITOR_SETTING):
+ editor_settings.erase(EXTERNAL_EDITOR_SETTING)
+
+# Register a single-entry enum so the persisted int doesn't render as a raw
+# number while async detection is in progress. register_rider_installations
+# replaces this once detection finishes.
+static func show_rider_searching_state() -> void:
+ # Order matters: `set` must come before `add_property_info` — the latter
+ # errors with `!props.has(pinfo.name)` if the property isn't in `props` yet.
+ var editor_settings := EditorInterface.get_editor_settings()
+ editor_settings.set(EXTERNAL_EDITOR_SETTING, 0)
+ editor_settings.add_property_info({
+ "name": EXTERNAL_EDITOR_SETTING,
+ "type": TYPE_INT,
+ "hint": PROPERTY_HINT_ENUM,
+ "hint_string": "Searching — reopen Settings to see the update",
+ })
+
+# Register the dropdown with one entry per detected installation (plus a "-"
+# placeholder at index 0) and select the given index.
+static func register_rider_installations(installations: Array, selected_index: int) -> void:
+ var editor_settings := EditorInterface.get_editor_settings()
+ var entries: Array = ["-"]
+ for element in installations:
+ var display_name: String = element.get("display", "")
+ entries.append(_escape_enum_label(display_name))
+ editor_settings.set(EXTERNAL_EDITOR_SETTING, selected_index)
+ editor_settings.add_property_info({
+ "name": EXTERNAL_EDITOR_SETTING,
+ "type": TYPE_INT,
+ "hint": PROPERTY_HINT_ENUM,
+ "hint_string": ",".join(entries),
+ })
+
+# Comma is the enum delimiter, colon introduces explicit value assignment.
+static func _escape_enum_label(s: String) -> String:
+ return s.replace(",", " •").replace(":", " -")
\ No newline at end of file
diff --git a/addons/rider-plugin/scripts/editor_settings_util.gd.uid b/addons/rider-plugin/scripts/editor_settings_util.gd.uid
new file mode 100644
index 0000000..3f50ddc
--- /dev/null
+++ b/addons/rider-plugin/scripts/editor_settings_util.gd.uid
@@ -0,0 +1 @@
+uid://bdiu78ot0rrkc
diff --git a/addons/rider-plugin/scripts/json_utils.gd b/addons/rider-plugin/scripts/json_utils.gd
new file mode 100644
index 0000000..660086b
--- /dev/null
+++ b/addons/rider-plugin/scripts/json_utils.gd
@@ -0,0 +1,23 @@
+@tool
+## Simple JSON helpers for editor/runtime use.
+## Keeps file and JSON parsing concerns out of feature code.
+class_name JsonUtils
+
+static func load_from_file(path: String) -> Variant:
+ # Returns parsed JSON value (Dictionary/Array/etc.) or null on error.
+ var file := FileAccess.open(path, FileAccess.READ)
+ if file == null:
+ push_warning("JsonUtils: Failed to open file: %s" % path)
+ return null
+ var text := file.get_as_text()
+ file.close()
+ var data: Variant = JSON.parse_string(text)
+ if data == null:
+ push_warning("JsonUtils: Invalid JSON in file: %s" % path)
+ return null
+ return data
+
+static func load_dict_from_file(path: String) -> Dictionary:
+ # Returns Dictionary or empty {} on error.
+ var data := load_from_file(path) as Dictionary
+ return data
diff --git a/addons/rider-plugin/scripts/json_utils.gd.uid b/addons/rider-plugin/scripts/json_utils.gd.uid
new file mode 100644
index 0000000..e780a44
--- /dev/null
+++ b/addons/rider-plugin/scripts/json_utils.gd.uid
@@ -0,0 +1 @@
+uid://bci4kmk7h4j6a
diff --git a/addons/rider-plugin/scripts/locator/rider_locator_service.gd b/addons/rider-plugin/scripts/locator/rider_locator_service.gd
new file mode 100644
index 0000000..45c1187
--- /dev/null
+++ b/addons/rider-plugin/scripts/locator/rider_locator_service.gd
@@ -0,0 +1,68 @@
+@tool
+extends RefCounted
+class_name RiderLocatorService
+
+var _installations_found: Array = []
+# we can keep a reference, it will be freed automatically, when the editor is closed
+var _rider_locator: RefCounted = null
+
+# Last value we wrote to / observed for the Rider selector dropdown
+var _last_selected_index: int = 0
+
+func start_search() -> void:
+ # use ClassDB to somehow still work without GDExtension part (in older Godot versions)
+ if not ClassDB.class_exists("RiderLocator"):
+ return
+
+ EditorSettingsUtil.show_rider_searching_state()
+ if _rider_locator == null:
+ _rider_locator = ClassDB.instantiate("RiderLocator")
+ _rider_locator.connect("installations_loaded", _on_installations_loaded)
+ _rider_locator.start_search()
+
+func _on_installations_loaded(array: Array) -> void:
+ _installations_found = array
+ _update_selector()
+
+func _update_selector() -> void:
+ if _installations_found.is_empty():
+ EditorSettingsUtil.erase_rider_external_editor_setting()
+ return
+
+ var index := _index_for_exec_path(_installations_found)
+ # Set _last_selected_index BEFORE register_rider_installations so the
+ # synchronous settings_changed handler sees a match and skips its work.
+ _last_selected_index = index
+ EditorSettingsUtil.register_rider_installations(_installations_found, index)
+
+ var settings_changed := EditorInterface.get_editor_settings().settings_changed
+ if not settings_changed.is_connected(_on_selection_changed):
+ settings_changed.connect(_on_selection_changed)
+
+func _index_for_exec_path(installations: Array) -> int:
+ var current := EditorSettingsUtil.get_external_editor_path()
+ if current.is_empty():
+ return 0
+ for i in installations.size():
+ if installations[i].get("path", "") == current:
+ return i + 1
+ return 0
+
+func _on_selection_changed() -> void:
+ var selected_index := EditorSettingsUtil.get_rider_selector_index()
+
+ # settings_changed fires for every editor setting, this helps to avoid updating on every other changes
+ if selected_index == _last_selected_index:
+ return
+ _last_selected_index = selected_index
+
+ # Index 0 is the placeholder, so the path is left untouched.
+ if selected_index == 0:
+ return
+
+ var installation_index := selected_index - 1
+ if installation_index >= 0 and installation_index < _installations_found.size():
+ var installation = _installations_found[installation_index]
+ var new_path: String = installation.get("path", "")
+ if not new_path.is_empty():
+ EditorSettingsUtil.set_external_editor_path(new_path)
diff --git a/addons/rider-plugin/scripts/locator/rider_locator_service.gd.uid b/addons/rider-plugin/scripts/locator/rider_locator_service.gd.uid
new file mode 100644
index 0000000..f7fcdaf
--- /dev/null
+++ b/addons/rider-plugin/scripts/locator/rider_locator_service.gd.uid
@@ -0,0 +1 @@
+uid://cfsu1rbg0ypem
diff --git a/addons/rider-plugin/scripts/presets/preset_applier.gd b/addons/rider-plugin/scripts/presets/preset_applier.gd
new file mode 100644
index 0000000..b09d025
--- /dev/null
+++ b/addons/rider-plugin/scripts/presets/preset_applier.gd
@@ -0,0 +1,35 @@
+@tool
+extends RefCounted
+class_name PresetApplier
+
+var presets_path: String
+
+func _init(p_path: String) -> void:
+ presets_path = p_path
+
+func get_preset_key(is_active: bool) -> String:
+ return "on" if is_active else "off"
+
+func apply_preset(editor_settings: EditorSettings, is_active: bool) -> void:
+ var data: Dictionary = JsonUtils.load_dict_from_file(presets_path)
+ if data.is_empty():
+ push_warning("Failed to load presets: %s" % presets_path)
+ return
+
+ var new_preset_key := get_preset_key(is_active)
+ var previous_preset_key := get_preset_key(not is_active)
+
+ if not data.has(new_preset_key):
+ push_warning("Preset '%s' not found in presets.json" % new_preset_key)
+ return
+
+ var new_preset := data[new_preset_key] as Dictionary
+ # Reset keys from previous preset that are missing in the new preset
+ if data.has(previous_preset_key):
+ var previous_preset := data[previous_preset_key] as Dictionary
+ for key in previous_preset:
+ if not new_preset.has(key):
+ editor_settings.set_setting(str(key), editor_settings.property_get_revert(str(key)))
+ # Apply the new preset
+ for key in new_preset:
+ editor_settings.set_setting(str(key), new_preset[key])
diff --git a/addons/rider-plugin/scripts/presets/preset_applier.gd.uid b/addons/rider-plugin/scripts/presets/preset_applier.gd.uid
new file mode 100644
index 0000000..af4fdde
--- /dev/null
+++ b/addons/rider-plugin/scripts/presets/preset_applier.gd.uid
@@ -0,0 +1 @@
+uid://bjiaycxso8h8u
diff --git a/project.godot b/project.godot
index 2fbb64d..d8692df 100644
--- a/project.godot
+++ b/project.godot
@@ -24,6 +24,10 @@ window/stretch/aspect="expand"
project/assembly_name="your are an ai ceo"
+[editor_plugins]
+
+enabled=PackedStringArray("res://addons/rider-plugin/plugin.cfg")
+
[physics]
2d/run_on_separate_thread=true
diff --git a/resources/meetings/coffee_meeting.tres b/resources/meetings/coffee_meeting.tres
index a0015bd..72ad40d 100644
--- a/resources/meetings/coffee_meeting.tres
+++ b/resources/meetings/coffee_meeting.tres
@@ -5,5 +5,5 @@
[resource]
script = ExtResource("1_s1cac")
Title = "Coffee Break"
-Color = Color(0.2210013, 0.40685424, 0.8183415, 1)
+Color = Color(0.31983396, 0.4835437, 0.33250993, 1)
metadata/_custom_type_script = "uid://cuq38lbfa2v74"
diff --git a/resources/meetings/lockin.tres b/resources/meetings/lockin.tres
new file mode 100644
index 0000000..eea9800
--- /dev/null
+++ b/resources/meetings/lockin.tres
@@ -0,0 +1,9 @@
+[gd_resource type="Resource" script_class="MeetingResource" format=3 uid="uid://du72uxjqr0h4a"]
+
+[ext_resource type="Script" uid="uid://cuq38lbfa2v74" path="res://resources/MeetingResource.cs" id="1_4yd4m"]
+
+[resource]
+script = ExtResource("1_4yd4m")
+Title = "LOCK IN"
+Color = Color(0.73206806, 0.22440341, 0.33911285, 1)
+metadata/_custom_type_script = "uid://cuq38lbfa2v74"
diff --git a/resources/meetings/work_product_1.tres b/resources/meetings/work_product_1.tres
new file mode 100644
index 0000000..5950a94
--- /dev/null
+++ b/resources/meetings/work_product_1.tres
@@ -0,0 +1,9 @@
+[gd_resource type="Resource" script_class="MeetingResource" format=3 uid="uid://bcd4qf4i84pwf"]
+
+[ext_resource type="Script" uid="uid://cuq38lbfa2v74" path="res://resources/MeetingResource.cs" id="1_qndny"]
+
+[resource]
+script = ExtResource("1_qndny")
+Title = "Work on your Product"
+Color = Color(0.4354798, 0.3262509, 0.83488727, 1)
+metadata/_custom_type_script = "uid://cuq38lbfa2v74"
diff --git a/your are an ai ceo.csproj b/your are an ai ceo.csproj
index 9898140..c939901 100644
--- a/your are an ai ceo.csproj
+++ b/your are an ai ceo.csproj
@@ -3,7 +3,7 @@
net8.0
net9.0
true
- yourareanaiceo
+ AiCeo
diff --git a/your are an ai ceo.sln.DotSettings.user b/your are an ai ceo.sln.DotSettings.user
new file mode 100644
index 0000000..453246d
--- /dev/null
+++ b/your are an ai ceo.sln.DotSettings.user
@@ -0,0 +1,2 @@
+
+ ForceIncluded
\ No newline at end of file