LogicLooper 1.6.0

dotnet add package LogicLooper --version 1.6.0                
NuGet\Install-Package LogicLooper -Version 1.6.0                
此命令旨在在 Visual Studio 的包管理器控制台中使用,因为它使用 NuGet 模块的 Install-Package 版本。
<PackageReference Include="LogicLooper" Version="1.6.0" />                
对于支持 PackageReference 的项目,请将此 XML 节点复制到项目文件以引用此包。
paket add LogicLooper --version 1.6.0                
#r "nuget: LogicLooper, 1.6.0"                
#r 指令可用于 F# Interactive 和 Polyglot Notebooks。将该指令复制到交互式工具或脚本的源代码中以引用包。
// Install LogicLooper as a Cake Addin
#addin nuget:?package=LogicLooper&version=1.6.0

// Install LogicLooper as a Cake Tool
#tool nuget:?package=LogicLooper&version=1.6.0                

Build-Master Releases

LogicLooper

日语

这个库是用来在 .NET 上使用循环动作编程模型构建服务器应用程序的。这个库专注于构建带服务器逻辑的游戏服务器。

例如,如果您有以下游戏循环,则库将提供一种比使用简单的 Task 更高效地聚合和处理的方式。

while (true)
{
    // some stuff to do ...
    network.Receive();
    world.Update();
    players.Update();
    network.Send();
    // some stuff to do ...

    // wait for next frame
    await Task.Delay(16);
}
using var looper = new LogicLooper(60);
await looper.RegisterActionAsync((in LogicLooperActionContext ctx) =>
{
    // The action will be called by looper every frame.
    // some stuff to do ...
    network.Receive();
    world.Update();
    players.Update();
    network.Send();
    // some stuff to do ...

    return true; // wait for next update
});

目录

安装

PS> Install-Package LogicLooper
$ dotnet add package LogicLooper

使用

单循环应用

Looper 绑定一个线程并开始一个主循环。您可以注册多个循环动作用于 Looper。这类似于在游戏引擎的一帧中调用多个 Update 方法。

using Cysharp.Threading;

// Create a looper.
const int targetFps = 60;
using var looper = new LogicLooper(targetFps);

// Register a action to the looper and wait for completion.
await looper.RegisterActionAsync((in LogicLooperActionContext ctx) =>
{
    // If you want to stop/complete the loop, return false to stop.
    if (...) { return false; }

    // some stuff to do ...

    return true; // wait for a next update.
});

使用 LooperPool 的多循环应用

例如,如果您的服务器有多个核心,运行多个循环将更有效。 LooperPool 提供了多个 Looper 和使用它们的界面。

using Cysharp.Threading;

// Create a looper pool.
// If your machine has 4-cores, the LooperPool creates 4-Looper instances.
const int targetFps = 60;
var looperCount = Environment.ProcessorCount;
using var looperPool = new LogicLooperPool(targetFps, looperCount, RoundRobinLogicLooperPoolBalancer.Instance);

// Register a action to the looper and wait for completion.
await looperPool.RegisterActionAsync((in LogicLooperActionContext ctx) =>
{
    // If you want to stop/complete the loop, return false to stop.
    if (...) { return false; }

    // some stuff to do ...

    return true; // wait for a next update.
});

与 Microsoft.Extensions.Hosting 集成

samples/LoopHostingApp

高级

单元测试 / 帧级执行

如果您想使用 LogicLooper 编写单元测试或手动更新帧,您可以使用 ManualLogicLooper / ManualLogicLooperPool

var looper = new ManualLogicLooper(60.0); // `ElapsedTimeFromPreviousFrame` will be fixed to `1000 / FrameTargetFrameRate`.

var count = 0;
var t1 = looper.RegisterActionAsync((in LogicLooperActionContext ctx) =>
{
    count++;
    return count != 3;
});

looper.Tick(); // Update frame
Console.WriteLine(count); // => 1

looper.Tick(); // Update frame
Console.WriteLine(count); // => 2

looper.Tick(); // Update frame (t1 will be completed)
Console.WriteLine(count); // => 3

looper.Tick(); // Update frame (no action)
Console.WriteLine(count); // => 3

协程

LogicLooper 支持类似协程的操作。如果您使用 Unity,您应该熟悉协程模式。

using var looper = new LogicLooper(60);

var coroutine = default(LogicLooperCoroutine);
await looper.RegisterActionAsync((in LogicLooperActionContext ctx) =>
{
    if (/* ... */)
    {
        // Launch a coroutine in the looper that same as the loop action.
        coroutine = ctx.RunCoroutine(async coCtx =>
        {
            // NOTE: `DelayFrame`, `DelayNextFrame`, `Delay` methods are allowed and awaitable in the coroutine.
            // If you await a Task or Task-like, the coroutine throws an exception.
            await coCtx.DelayFrame(60);

            // some stuff to do ...

            await coCtx.DelayNextFrame();

            // some stuff to do ...

            await coCtx.Delay(TimeSpan.FromMilliseconds(16.66666));
        });
    }

    if (coroutine.IsCompleted)
    {
        // When the coroutine has completed, you can do some stuff ...
    }

    return true;
});

TargetFrameRateOverride

TargetFrameRateOverride 选项允许覆盖每个动作的帧率。这在需要混合多个帧率的情况下很有用,比如期望主循环以 30fps 运行,但某些动作需要在 5fps 下调用。

您还可以设置每个执行循环的 Looper 的帧率,但由于 LogicLooper 的设计是每个线程 1 个循环,所以在原则上我们希望 Loopers 的数量与核心数相符。通过为每个动作设置帧率,即使在工作量变化的情况下,也可以保持 Loopers 的数量不变。

using var looper = new LogicLooper(60); // 60 fps

await looper.RegisterActionAsync((in LogicLooperActionContext ctx) =>
{
    // Something to do ...
    return true;
}); // The action will be called at 60fps.

await looper.RegisterActionAsync((in LogicLooperActionContext ctx) =>
{
    // Something to do (low priority) ...
    return true;
}, LooperActionOptions.Default with { TargetFrameRateOverride = 10 }); // The action will be called at 10fps.

动作执行的粒度会根据主循环的执行频率而变化。这意味着准确性可能低于 Looper 的目标帧率。

实验性

async-aware loop actions

对可等待异步事件的循环动作的实验性支持。

使用 SynchronizationContext,所有异步延续都将在循环线程上执行。请注意,与同步操作不同,异步操作会跨越多个帧执行。

await looper.RegisterActionAsync(static async (ctx, state) =>
{
    state.Add("1"); // Frame: 1
    await Task.Delay(250);
    state.Add("2"); // Frame: 2 or later
    return false;
});

[!警告] 如果动作立即完成(ValueTask.IsCompleted = true),与非异步版本相比没有性能差异。但如果需要等待,则速度非常慢。这一异步支持作为一个紧急出口,当需要以低频率与外部进行通信时。我们不建议以高频率进行异步处理。

产品 兼容的和额外的计算目标框架版本。
.NET net5.0 已计算。 net5.0-windows 已计算。 net6.0 兼容。 net6.0-android 已计算。 net6.0-ios 已计算。 net6.0-maccatalyst 已计算。 net6.0-macos 已计算。 net6.0-tvos 已计算。 net6.0-windows 已计算。 net7.0 已计算。 net7.0-android 已计算。 net7.0-ios 已计算。 net7.0-maccatalyst 已计算。 net7.0-macos 已计算。 net7.0-tvos 已计算。 net7.0-windows 已计算。 net8.0 兼容。 net8.0-android 已计算。 net8.0-browser 已计算。 net8.0-ios 已计算。 net8.0-maccatalyst 已计算。 net8.0-macos 已计算。 net8.0-tvos 已计算。 net8.0-windows 已计算。
.NET Core netcoreapp2.0 已计算。 netcoreapp2.1 已计算。 netcoreapp2.2 已计算。 netcoreapp3.0 已计算。 netcoreapp3.1 已计算。
.NET Standard netstandard2.0 兼容。 netstandard2.1 兼容。
.NET Framework net461 已计算。 net462 已计算。 net463 已计算。 net47 已计算。 net471 已计算。 net472 已计算。 net48 已计算。 net481 已计算。
MonoAndroid monoandroid 已计算。
MonoMac monomac 已计算。
MonoTouch monotouch 已计算。
Tizen tizen40 已计算。 tizen60 已计算。
Xamarin.iOS xamarinios 已计算。
Xamarin.Mac xamarinmac 已计算。
Xamarin.TVOS xamarintvos 已计算。
Xamarin.WatchOS xamarinwatchos 已计算。
兼容目标框架
包含的目标框架(在包中)
了解更多关于 目标框架.NET Standard 的信息。

NuGet 包 (1)

展示依赖于 LogicLooper 的前 1 个 NuGet 包

下载
R3Extensions.LogicLooper

为 R3 提供的 LogicLooper 属性和方法。

GitHub 仓库

此包不被流行的 GitHub 仓库所使用。

版本 下载 最后更新
1.6.0 5,454 5/2/2024
1.5.0 3,103 2/14/2024
1.4.0 9,518 11/20/2023
1.3.0 2,996 8/4/2023
1.2.0 255 8/2/2023
1.1.0 73,144 10/18/2021
1.0.2 19,399 3/18/2020
1.0.1 489 3/17/2020
1.0.0 455 3/16/2020
1.0.0-beta-2 373 3/13/2020
1.0.0-beta-1 347 3/13/2020