Skip to content

Commit 62c261a

Browse files
committed
Merge branch 'S1P4_Develop' into main
2 parents 2eb2a9b + b161942 commit 62c261a

File tree

25 files changed

+292
-61
lines changed

25 files changed

+292
-61
lines changed

Lessons/.gdignore

Whitespace-only changes.

Lessons/1/User/ThreeStar.sfc

0 Bytes
Binary file not shown.

Lessons/1/User/TwoStar.sfc

0 Bytes
Binary file not shown.

data/core/environment/EnvironmentPaths.cs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,47 @@ namespace Osls.Environment
33
public static class EnvironmentPaths
44
{
55
/// <summary>
6-
/// Gets the globalized lesson folder path
6+
/// Gets the forced globalized lesson folder path.
7+
/// ProjectSettings.GlobalizePath will not return the system path for res:// in export
8+
/// Currently there seems to be no way to get the execution folder directly,
9+
/// but we can use the exe path but only in export mode.
710
/// </summary>
811
public static string LessonsFolderPath
912
{
1013
get
1114
{
12-
return Godot.ProjectSettings.GlobalizePath("res://lessons/");
15+
string path = Godot.ProjectSettings.GlobalizePath(InternalLessonsFolderPath);
16+
if (path.Contains(":"))
17+
{
18+
return path;
19+
}
20+
path = Godot.OS.GetExecutablePath();
21+
int lastIndex = path.LastIndexOf("/");
22+
path = path.Substring(0, lastIndex + 1);
23+
return path + "lessons/";
24+
}
25+
}
26+
27+
/// <summary>
28+
/// Gets the globalized alternative lesson folder path if the regular does not work.
29+
/// Especially used for MacOS as the res path is not writeable.
30+
/// </summary>
31+
public static string LessonsFolderPathAlternative
32+
{
33+
get
34+
{
35+
return Godot.ProjectSettings.GlobalizePath("user://lessons/");
36+
}
37+
}
38+
39+
/// <summary>
40+
/// Gets the internal packed lesson folder path. Read only.
41+
/// </summary>
42+
public static string InternalLessonsFolderPath
43+
{
44+
get
45+
{
46+
return "res://lessons/";
1347
}
1448
}
1549
}

data/core/landing_page/LandingPage.tscn

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
[gd_scene load_steps=6 format=2]
1+
[gd_scene load_steps=7 format=2]
22

33
[ext_resource path="res://data/core/landing_page/LandingPageNode.cs" type="Script" id=1]
44
[ext_resource path="res://data/core/landing_page/LessonsNode.cs" type="Script" id=2]
55
[ext_resource path="res://data/core/landing_page/LessonSelectionGridNode.cs" type="Script" id=3]
66
[ext_resource path="res://data/core/lesson/viewer/LessonView.tscn" type="PackedScene" id=4]
77
[ext_resource path="res://data/core/landing_page/lesson_source_controller/images/DiagramScreenshot.png" type="Texture" id=5]
8+
[ext_resource path="res://data/core/landing_page/lesson_source_controller/LessonController.tscn" type="PackedScene" id=6]
89

910
[node name="LandingPage" type="Node"]
1011
script = ExtResource( 1 )
@@ -19,6 +20,9 @@ margin_left = 80.0
1920
margin_top = 1.0
2021
margin_right = -513.0
2122
rect_clip_content = true
23+
__meta__ = {
24+
"_edit_use_anchors_": false
25+
}
2226

2327
[node name="Background" type="TextureRect" parent="LessonsNode/LessonSelectorContainer"]
2428
modulate = Color( 0.956863, 0.94902, 0.917647, 1 )
@@ -53,6 +57,7 @@ custom_constants/vseparation = 50
5357
custom_constants/hseparation = 50
5458
columns = 4
5559
script = ExtResource( 3 )
60+
_lessonControllerScene = ExtResource( 6 )
5661

5762
[node name="LessonPreviewBackground" type="ColorRect" parent="LessonsNode"]
5863
anchor_left = 1.0

data/core/landing_page/LessonSelectionGridNode.cs

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using Godot;
2-
using Osls.Environment;
32

43

54
namespace Osls.LandingPage
@@ -11,7 +10,7 @@ namespace Osls.LandingPage
1110
public class LessonSelectionGridNode : GridContainer
1211
{
1312
#region ==================== Fields ====================
14-
private const string LessonControllerScene = "res://data/core/landing_page/lesson_source_controller/LessonController.tscn";
13+
[Export] private PackedScene _lessonControllerScene;
1514
private LessonControllerNode[] _lessonNodes;
1615
#endregion
1716

@@ -21,7 +20,7 @@ public override void _Ready()
2120
{
2221
try
2322
{
24-
LessonEntity[] lessons = LoadLessons();
23+
LessonEntity[] lessons = LessonCollector.LoadLessons();
2524
CreateButtons(lessons);
2625
}
2726
catch (System.Exception e)
@@ -57,28 +56,13 @@ public void StartSelectedLesson(LessonControllerNode node)
5756
#endregion
5857

5958

60-
#region ==================== Private Methods ====================
61-
private LessonEntity[] LoadLessons()
62-
{
63-
string[] LessonPaths = System.IO.Directory.GetDirectories(EnvironmentPaths.LessonsFolderPath);
64-
System.Array.Sort<string>(LessonPaths);
65-
LessonEntity[] lessonEntities = new LessonEntity[LessonPaths.Length];
66-
for (int i = 0; i < LessonPaths.Length; i++)
67-
{
68-
LessonEntity lessonData = new LessonEntity(LessonPaths[i]);
69-
lessonData.LoadFolderContent();
70-
lessonEntities[i] = lessonData;
71-
}
72-
return lessonEntities;
73-
}
74-
59+
#region ==================== Helpers ====================
7560
private void CreateButtons(LessonEntity[] lessons)
7661
{
77-
PackedScene packedControllerNode = (PackedScene)GD.Load(LessonControllerScene);
7862
_lessonNodes = new LessonControllerNode[lessons.Length];
7963
for (int i = 0; i < lessons.Length; i++)
8064
{
81-
LessonControllerNode controllerNode = (LessonControllerNode)packedControllerNode.Instance();
65+
LessonControllerNode controllerNode = (LessonControllerNode)_lessonControllerScene.Instance();
8266
controllerNode.SetLessonInfo(lessons[i], this);
8367
AddChild(controllerNode);
8468
_lessonNodes[i] = controllerNode;

data/core/lesson/LessonCollector.cs

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
using Godot;
2+
using Osls.Environment;
3+
4+
5+
namespace Osls
6+
{
7+
public static class LessonCollector
8+
{
9+
#region ==================== Public Methods ====================
10+
/// <summary>
11+
/// Loads all aviable lessons at the locations:
12+
/// res://lessons/ and as an alternative user://lesons
13+
/// If it does not exist we try to create a default directory at
14+
/// res://lessons/ and as an alternative user://lesons
15+
/// </summary>
16+
public static LessonEntity[] LoadLessons()
17+
{
18+
string[] LessonPaths = GetLessonPaths();
19+
System.Array.Sort<string>(LessonPaths);
20+
LessonEntity[] lessonEntities = new LessonEntity[LessonPaths.Length];
21+
for (int i = 0; i < LessonPaths.Length; i++)
22+
{
23+
LessonEntity lessonData = new LessonEntity(LessonPaths[i]);
24+
lessonData.LoadFolderContent();
25+
lessonEntities[i] = lessonData;
26+
}
27+
return lessonEntities;
28+
}
29+
#endregion
30+
31+
32+
#region ==================== Helpers ====================
33+
/// <summary>
34+
/// Gets the base directories for the lesson folders.
35+
/// It first looks under the res folder and then in the user path.
36+
/// If none could be found we create a new dir and copy the default data in it.
37+
/// </summary>
38+
private static string[] GetLessonPaths()
39+
{
40+
string[] LessonPaths = TryLoad(EnvironmentPaths.LessonsFolderPath);
41+
if (LessonPaths != null && LessonPaths.Length > 0) return LessonPaths;
42+
LessonPaths = TryLoad(EnvironmentPaths.LessonsFolderPathAlternative);
43+
if (LessonPaths != null && LessonPaths.Length > 0) return LessonPaths;
44+
if (CreateDefault(EnvironmentPaths.LessonsFolderPath))
45+
{
46+
return TryLoad(EnvironmentPaths.LessonsFolderPath);
47+
}
48+
if (CreateDefault(EnvironmentPaths.LessonsFolderPathAlternative))
49+
{
50+
return TryLoad(EnvironmentPaths.LessonsFolderPathAlternative);
51+
}
52+
GD.PushWarning("Could not find any lessons at: " + EnvironmentPaths.LessonsFolderPath + " and " + EnvironmentPaths.LessonsFolderPathAlternative);
53+
return new string[0];
54+
}
55+
56+
private static string[] TryLoad(string path)
57+
{
58+
if (!System.IO.Directory.Exists(path)) return new string[0];
59+
return System.IO.Directory.GetDirectories(path);
60+
}
61+
62+
/// <summary>
63+
/// Returns true if the default files could be copied to the base path
64+
/// </summary>
65+
private static bool CreateDefault(string basePath)
66+
{
67+
GD.Print("Try to copy " + EnvironmentPaths.InternalLessonsFolderPath + " to " + basePath);
68+
Directory targetDir = new Directory();
69+
Directory internalDir = new Directory();
70+
Error result = targetDir.MakeDirRecursive(basePath);
71+
Error internalresult = internalDir.Open(EnvironmentPaths.InternalLessonsFolderPath);
72+
if (result != Error.Ok || internalresult != Error.Ok) return false;
73+
ProcessDirectory(EnvironmentPaths.InternalLessonsFolderPath, basePath);
74+
return true;
75+
}
76+
77+
/// <summary>
78+
/// Copies all files from the given internal directory to the given path.
79+
/// As the internal data is packed we need to use godots directory system.
80+
/// </summary>
81+
private static void ProcessDirectory(string internalPath, string externalPath)
82+
{
83+
Directory internalDir = new Directory();
84+
Error result = internalDir.Open(internalPath);
85+
if (result != Error.Ok) return;
86+
internalDir.ListDirBegin(true, true);
87+
while (true)
88+
{
89+
string item = internalDir.GetNext();
90+
if (string.IsNullOrEmpty(item)) return;
91+
if (internalDir.CurrentIsDir())
92+
{
93+
Directory targetDir = new Directory();
94+
GD.Print("create " + externalPath + item + "/");
95+
targetDir.MakeDir(externalPath + item + "/");
96+
ProcessDirectory(internalPath + item + "/", externalPath + item + "/");
97+
}
98+
else
99+
{
100+
GD.Print("copy " + internalPath + item + " to " + externalPath + item);
101+
internalDir.Copy(internalPath + item, externalPath + item);
102+
}
103+
}
104+
}
105+
#endregion
106+
}
107+
}

data/core/lesson/LessonController.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public class LessonController
1313
private const string EditorPath = "res://data/diagram_models/sfc/editor/SfcEditor.tscn";
1414
private const string SimulationPath = "res://data/diagram_models/sfc/processing_viewer/SfcSimulationViewer.tscn";
1515
private readonly MainNode _mainNode;
16-
private LessonEntity _opendLesson;
16+
private LessonEntity _openedLesson;
1717

1818
private PageModule _currentPage;
1919
#endregion
@@ -33,7 +33,7 @@ public LessonController(MainNode mainNode)
3333
/// </summary>
3434
public void ApplyNewLesson(LessonEntity lesson)
3535
{
36-
_opendLesson = lesson;
36+
_openedLesson = lesson;
3737
}
3838

3939
/// <summary>
@@ -79,26 +79,26 @@ private void LoadNewScene(PageCategory view)
7979
scene = ((PackedScene)GD.Load(EditorPath)).Instance() as PageModule;
8080
break;
8181
case PageCategory.Simulation:
82-
if (!string.IsNullOrEmpty(_opendLesson.SimulationPath))
82+
if (!string.IsNullOrEmpty(_openedLesson.SimulationPath))
8383
{
8484
scene = ((PackedScene)GD.Load(SimulationPath)).Instance() as PageModule;
8585
}
8686
break;
8787
case PageCategory.Examination:
88-
if (!string.IsNullOrEmpty(_opendLesson.TestPath))
88+
if (!string.IsNullOrEmpty(_openedLesson.TestPath))
8989
{
90-
scene = ((PackedScene)GD.Load(_opendLesson.TestPath)).Instance() as PageModule;
90+
scene = ((PackedScene)GD.Load(_openedLesson.TestPath)).Instance() as PageModule;
9191
}
9292
break;
9393
}
9494
_currentPage = scene;
9595
if (_currentPage != null)
9696
{
97-
_currentPage.InitialiseWith(_mainNode, _opendLesson);
97+
_currentPage.InitialiseWith(_mainNode, _openedLesson);
9898
_mainNode.AddChild(_currentPage);
9999
_mainNode.MoveChild(_currentPage, 0);
100100
}
101101
}
102102
#endregion
103103
}
104-
}
104+
}

data/core/lesson/LessonEntity.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ public void SetAndSaveStars(int stars)
118118
#region ==================== Helpers ====================
119119
/// <summary>
120120
/// Loads the description json as a godot dictionary.
121-
/// It is different than the System.Runtime.Serialization json attribute deserilisation.
121+
/// It is different than the System.Runtime.Serialization json attribute deserialization.
122122
/// But it is sufficient for our needs.
123123
/// </summary>
124124
private void LoadDescriptionDictionary()

data/core/scene_manager/MainNode.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class MainNode : Node
1919
#region ==================== Public Methods ====================
2020
public override void _Ready()
2121
{
22+
HandleWindow();
2223
_lessonController = new LessonController(this);
2324
_navigationSteps = GetNode<NavigationSteps>("NavigationSteps");
2425
ChangePageTo(PageCategory.LandingPage);
@@ -43,7 +44,7 @@ public void OpenNewLesson(LessonEntity lessonData)
4344

4445
/// <summary>
4546
/// Requests a change of the current page to the new page.
46-
/// Used to privide the possibility for the user to save or cancel the action.
47+
/// Used to provide the possibility for the user to save or cancel the action.
4748
/// </summary>
4849
public void UserRequestsChangeTo(PageCategory page)
4950
{
@@ -63,6 +64,11 @@ public void ChangePageTo(PageCategory page)
6364

6465

6566
#region ==================== Helpers ====================
67+
private void HandleWindow()
68+
{
69+
OS.WindowMaximized = true;
70+
}
71+
6672
private void QuitSfcSandbox()
6773
{
6874
GetTree().Quit();

0 commit comments

Comments
 (0)