97 lines
2.3 KiB
C#
97 lines
2.3 KiB
C#
#nullable enable
|
|
|
|
using System;
|
|
using System.Threading;
|
|
using EntJoy.ECS;
|
|
using EntJoy.JobSystem;
|
|
using Godot;
|
|
using ShrinkSDK.Godot;
|
|
|
|
namespace ShrinkSDK.EntJoy.Godot;
|
|
|
|
/// <summary>Godot node that owns an EntJoy World and advances its frame boundary.</summary>
|
|
public partial class ShrinkEntJoyHost : ShrinkGodotHost
|
|
{
|
|
private static readonly object SchedulerGate = new();
|
|
private static int SchedulerUsers;
|
|
private bool _schedulerAcquired;
|
|
private bool _worldDisposed;
|
|
private ulong _lastFrame = ulong.MaxValue;
|
|
private SceneTree? _tree;
|
|
|
|
[Export] public string EntJoyWorldName { get; set; } = "GodotWorld";
|
|
|
|
public World? EntJoyWorld { get; private set; }
|
|
|
|
public override void _Ready()
|
|
{
|
|
base._Ready();
|
|
AcquireScheduler();
|
|
EntJoyWorld = new World(EntJoyWorldName);
|
|
World.DefaultWorld = EntJoyWorld;
|
|
_tree = GetTree();
|
|
_tree.ProcessFrame += OnProcessFrame;
|
|
TreeExited += OnTreeExited;
|
|
}
|
|
|
|
public override void _Process(double delta)
|
|
{
|
|
base._Process(delta);
|
|
Advance();
|
|
}
|
|
|
|
private void OnProcessFrame() => Advance();
|
|
|
|
private void Advance()
|
|
{
|
|
if (EntJoyWorld == null || _worldDisposed) return;
|
|
var frame = Engine.GetProcessFrames();
|
|
if (frame == _lastFrame) return;
|
|
_lastFrame = frame;
|
|
EntJoyWorld.NextFrameEvents();
|
|
NativeJobScheduler.EndFrame();
|
|
EntJoyWorld.CurrentFrame++;
|
|
}
|
|
|
|
public override void _ExitTree()
|
|
{
|
|
DisposeWorld();
|
|
base._ExitTree();
|
|
}
|
|
|
|
private void OnTreeExited()
|
|
{
|
|
if (_tree != null)
|
|
_tree.ProcessFrame -= OnProcessFrame;
|
|
_tree = null;
|
|
TreeExited -= OnTreeExited;
|
|
DisposeWorld();
|
|
}
|
|
|
|
private void AcquireScheduler()
|
|
{
|
|
lock (SchedulerGate)
|
|
{
|
|
if (SchedulerUsers++ == 0)
|
|
NativeJobScheduler.Initialize();
|
|
_schedulerAcquired = true;
|
|
}
|
|
}
|
|
|
|
private void DisposeWorld()
|
|
{
|
|
if (_worldDisposed) return;
|
|
_worldDisposed = true;
|
|
EntJoyWorld?.Dispose();
|
|
EntJoyWorld = null;
|
|
|
|
if (!_schedulerAcquired) return;
|
|
lock (SchedulerGate)
|
|
{
|
|
_schedulerAcquired = false;
|
|
if (--SchedulerUsers == 0)
|
|
NativeJobScheduler.Shutdown();
|
|
}
|
|
}
|
|
}
|