Skip to content

Commit

Permalink
Godot support
Browse files Browse the repository at this point in the history
  • Loading branch information
neuecc committed Jan 7, 2024
1 parent 97d9562 commit c9c7d31
Show file tree
Hide file tree
Showing 15 changed files with 365 additions and 15 deletions.
11 changes: 9 additions & 2 deletions R3.sln
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "R3.WPF", "src\R3.WPF\R3.WPF
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfApp1", "sandbox\WpfApp1\WpfApp1.csproj", "{BA40E541-3BCD-438A-B966-2FC7BE80AB80}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "R3.Avalonia", "src\R3.Avalonia\R3.Avalonia.csproj", "{C492C048-732F-4F0D-AC09-03F3187ABB17}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "R3.Avalonia", "src\R3.Avalonia\R3.Avalonia.csproj", "{C492C048-732F-4F0D-AC09-03F3187ABB17}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AvaloniaApplication1", "sandbox\AvaloniaApplication1\AvaloniaApplication1.csproj", "{978BECEF-5217-4531-B0B7-45BC8D820A28}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AvaloniaApplication1", "sandbox\AvaloniaApplication1\AvaloniaApplication1.csproj", "{978BECEF-5217-4531-B0B7-45BC8D820A28}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "R3.Godot", "src\R3.Godot\R3.Godot.csproj", "{B7A5DDB0-5F43-49D0-A047-D0D26626BE30}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -64,6 +66,10 @@ Global
{978BECEF-5217-4531-B0B7-45BC8D820A28}.Debug|Any CPU.Build.0 = Debug|Any CPU
{978BECEF-5217-4531-B0B7-45BC8D820A28}.Release|Any CPU.ActiveCfg = Release|Any CPU
{978BECEF-5217-4531-B0B7-45BC8D820A28}.Release|Any CPU.Build.0 = Release|Any CPU
{B7A5DDB0-5F43-49D0-A047-D0D26626BE30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B7A5DDB0-5F43-49D0-A047-D0D26626BE30}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B7A5DDB0-5F43-49D0-A047-D0D26626BE30}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B7A5DDB0-5F43-49D0-A047-D0D26626BE30}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -76,6 +82,7 @@ Global
{BA40E541-3BCD-438A-B966-2FC7BE80AB80} = {FAB2137C-1DBA-4F2F-8E22-DF3521C9B365}
{C492C048-732F-4F0D-AC09-03F3187ABB17} = {9FA6D327-728B-4436-AE3A-9E46D8FEF591}
{978BECEF-5217-4531-B0B7-45BC8D820A28} = {FAB2137C-1DBA-4F2F-8E22-DF3521C9B365}
{B7A5DDB0-5F43-49D0-A047-D0D26626BE30} = {9FA6D327-728B-4436-AE3A-9E46D8FEF591}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {84B77761-6B9E-46BA-B132-6C77B0B6E4FA}
Expand Down
2 changes: 1 addition & 1 deletion src/R3.Avalonia/AvaloniaDispatcherFrameProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using R3.Collections;
using System.Diagnostics.CodeAnalysis;

namespace R3.Avalonia;
namespace R3;

// like the Avalonia.Rendering.UiThreadRenderTimer

Expand Down
2 changes: 1 addition & 1 deletion src/R3.Avalonia/AvaloniaDispatcherTimerProvider.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Avalonia.Threading;

namespace R3.Avalonia;
namespace R3;

public sealed class AvaloniaDispatcherTimerProvider : TimeProvider
{
Expand Down
2 changes: 1 addition & 1 deletion src/R3.Avalonia/AvaloniaProviderInitializer.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Avalonia.Logging;
using Avalonia.Threading;

namespace R3.Avalonia;
namespace R3;

public static class AvaloniaProviderInitializer
{
Expand Down
21 changes: 21 additions & 0 deletions src/R3.Godot/R3.Godot.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>

<!-- Currently no packable -->
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="GodotSharp" Version="4.2.1" />
<!--<PackageReference Include="Godot.SourceGenerators" Version="4.2.1" />-->
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\R3\R3.csproj" />
</ItemGroup>

</Project>
31 changes: 31 additions & 0 deletions src/R3.Godot/addons/R3.Godot/FrameProviderDispatcher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#nullable enable

using System.Runtime.CompilerServices;

namespace R3;

public partial class FrameProviderDispatcher : global::Godot.Node
{
StrongBox<double> processDelta = new StrongBox<double>();
StrongBox<double> physicsProcessDelta = new StrongBox<double>();

public override void _Ready()
{
GodotProviderInitializer.SetDefaultObservableSystem();

((GodotFrameProvider)GodotFrameProvider.Process).Delta = processDelta;
((GodotFrameProvider)GodotFrameProvider.PhysicsProcess).Delta = physicsProcessDelta;
}

public override void _Process(double delta)
{
processDelta.Value = delta;
((GodotFrameProvider)GodotFrameProvider.Process).Run(delta);
}

public override void _PhysicsProcess(double delta)
{
physicsProcessDelta.Value = delta;
((GodotFrameProvider)GodotFrameProvider.PhysicsProcess).Run(delta);
}
}
80 changes: 80 additions & 0 deletions src/R3.Godot/addons/R3.Godot/GodotFrameProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#nullable enable

using Godot;
using R3.Collections;
using System;
using System.Runtime.CompilerServices;

namespace R3;

internal enum PlayerLoopTiming
{
Process,
PhysicsProcess
}

public class GodotFrameProvider : FrameProvider
{
public static readonly FrameProvider Process = new GodotFrameProvider(PlayerLoopTiming.Process);
public static readonly FrameProvider PhysicsProcess = new GodotFrameProvider(PlayerLoopTiming.PhysicsProcess);

FreeListCore<IFrameRunnerWorkItem> list;
readonly object gate = new object();

PlayerLoopTiming PlayerLoopTiming { get; }

internal StrongBox<double> Delta = default!; // set from Node before running process.

internal GodotFrameProvider(PlayerLoopTiming playerLoopTiming)
{
this.PlayerLoopTiming = playerLoopTiming;
this.list = new FreeListCore<IFrameRunnerWorkItem>(gate);
}

public override long GetFrameCount()
{
if (PlayerLoopTiming == PlayerLoopTiming.Process)
{
return (long)Engine.GetProcessFrames();
}
else
{
return (long)Engine.GetPhysicsFrames();
}
}

public override void Register(IFrameRunnerWorkItem callback)
{
list.Add(callback, out _);
}

internal void Run(double _)
{
long frameCount = GetFrameCount();

var span = list.AsSpan();
for (int i = 0; i < span.Length; i++)
{
ref readonly var item = ref span[i];
if (item != null)
{
try
{
if (!item.MoveNext(frameCount))
{
list.Remove(i);
}
}
catch (Exception ex)
{
list.Remove(i);
try
{
ObservableSystem.GetUnhandledExceptionHandler().Invoke(ex);
}
catch { }
}
}
}
}
}
21 changes: 21 additions & 0 deletions src/R3.Godot/addons/R3.Godot/GodotProviderInitializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#nullable enable

using Godot;
using System;

namespace R3;

public static class GodotProviderInitializer
{
public static void SetDefaultObservableSystem()
{
SetDefaultObservableSystem(ex => GD.PrintErr(ex));
}

public static void SetDefaultObservableSystem(Action<Exception> unhandledExceptionHandler)
{
ObservableSystem.RegisterUnhandledExceptionHandler(unhandledExceptionHandler);
ObservableSystem.DefaultTimeProvider = GodotTimeProvider.Process;
ObservableSystem.DefaultFrameProvider = GodotFrameProvider.PhysicsProcess;
}
}
Loading

0 comments on commit c9c7d31

Please sign in to comment.