Understanding the Engine

The Altruist Engine is a highly optimized game loop that lives inside the Gaming Layer of the Altruist framework. It is specifically designed for games, physics simulations, and other real-time actions that require consistent, frame-based updates.

It provides frame-based execution, ensuring that game logic that uses physics run at a consistent rate to simulate realistic and smooth behaviors.

Note:

When do you need it?


Ask yourself: do you need to run something periodically or simulate real-time behavior on the server? If the answer is yes, read further.

Enabling the Engine

By default, Altruist runs without an internal game loop. To enable the engine, replace .NoEngine() with .EnableEngine(FrameRate.Hz30). This sets up an internal loop running at 30Hz (30 cycles per defined unit).

AltruistBuilder.Create(args)
    .SetupGameEngine(setup => setup
        .AddWorld(new MainWorldIndex(0, new Vector2(100, 100)))
        .EnableEngine(FrameRate.Hz30))
    .WithWebsocket(setup => setup.MapPortal<SimpleGamePortal>("/game"))
    .WithRedis(setup => setup.AddDocument<Spaceship>())
    .WebApp() // for websockets we need a WebApp
    .StartServer();

You can increase the frame rate to higher values if needed:

.EnableEngine(FrameRate.Hz60) // 60 cycles per defined unit
or
.EnableEngine(FrameRate.Hz120) // 120 cycles per defined unit

Note:

Higher frame rates improve real-time responsiveness but also increase CPU usage. Choose a frame rate that balances performance and smoothness based on your game's needs.

Note:

Once you enable the engine, responses to clients are no longer sent on demand. Instead, the engine manages the updates, ensuring that only the latest necessary data is delivered. This optimizes bandwidth usage and ensures consistency across all connected clients.

Scheduling Tasks in the Engine

Once the engine is enabled, tasks can be scheduled to run at specific intervals or frequencies.

Using ScheduleTask()

The ScheduleTask method allows tasks to execute at a specified cycle rate. If no rate is provided, the task runs at the engine’s default frame rate.

engine.ScheduleTask(Save, saveStrategy.SaveRate);

The saveStrategy.SaveRate is an instance of CycleRate, which defines how frequently a task runs.

Understanding CycleRate

The CycleRate determines how often a task runs:

Cycle UnitMeaning
Seconds30Hz → Runs 30 times per second (fast)
Milliseconds30Hz → Runs 30 times per millisecond (super fast)
Ticks30Hz → Runs once every 30 CPU ticks (extremely fast)

Note:

Note: A higher Hz means faster execution for time-based units (Seconds, Milliseconds), but for Ticks, a higher Hz results in slower execution.

Example: Running a Task Faster Than the Engine Rate
If the engine runs at 30Hz, but a regeneration system needs 120Hz, we can specify:

engine.ScheduleTask(RegenerateHealth, new CycleRate(120, CycleUnit.Seconds));

This ensures health regeneration updates occur 4x faster than the engine frame rate, if the engine cycle rate is 30Hz and also defined in seconds.

Note:

If the engine uses a different CycleUnit (e.g., Ticks or Milliseconds), the actual execution frequency will depend on the unit conversion.

Using RegisterCronJob()

For non-frequent periodic updates (e.g., saving player data every minute), use RegisterCronJob.

engine.RegisterCronJob(Save, saveStrategy.CronExpression);

The CronExpression follows standard cron syntax e.g.:

ExpressionExecution Frequency
"*/1 * * * *"Every 1 minute
"0 * * * *"Every hour
"0 0 * * *"Once per day

Note:

Use case: Scheduled tasks like database backups, leaderboard resets, and daily rewards.

Cycle Attribute

The Cycle attribute in Altruist is used to annotate methods that you wish to execute on the engine. This attribute allows you to define a schedule for task execution using either cron expressions, frequency in Hertz, or real-time execution. It provides a way to automate method scheduling without manually calling ScheduleTask.

How It Works

The CycleAttribute can be used to specify different scheduling strategies based on the method's needs:

Properties of CycleAttribute

  • Cron: Defines a cron expression to schedule the method execution.
  • Rate: Defines the frequency in Hertz to schedule the method execution.
  • Realtime: A boolean flag that determines if the method should execute in real-time, meaning it will match the engine's update frequency.

Example of the CycleAttribute Usage

Here’s an example of using the Cycle attribute to schedule a method:

[Cycle(30)] // Executes 30 times per second (30Hz)
public Task UpdateGameState()
{
    // Task logic
}

This will ensure that UpdateGameState is executed at 30Hz.

Understanding the CycleAttribute Properties

1. Cron Expression

A cron expression allows you to specify the method's schedule using a string. This is useful for tasks that need to run at fixed intervals, such as daily or hourly operations.

Example:

[Cycle("0 0 * * *")] // Runs once per day
public Task DailyCleanup()
{
    // Task logic
}

In this example, the DailyCleanup method will be executed once every day at midnight, based on the cron expression 0 0 * * *.

  1. Frequency in Hertz

The frequency property allows you to specify how often the method should execute in Hertz (Hz). Hertz refers to the number of cycles per defined unit. For example, 30Hz means the task will execute 30 times per defined unit.

You can define a method to run at a specific frequency:

[Cycle(120, CycleUnit.Seconds)] // Executes 120 times per second
public Task RegenerateHealth()
{
    // Task logic
}

In this case, the ``RegenerateHealth` method will be executed 120 times per second. By default, if no frequency is provided, the task will run at the engine’s default frame rate.

  1. Real-Time Execution

The Realtime property indicates that the method should match the engine's update frequency. This is useful when you want the method to run in sync with the engine, ensuring it doesn’t get out of sync with the overall game loop.

[Cycle] // Executes in real-time, matching the engine's frame rate
public Task RealTimeUpdate()
{
    // Task logic
}

This method will execute at the engine's frame rate, making it ideal for tasks that need to run alongside the main game loop.

Summary

  • Enable the engine using .EnableEngine(FrameRate.HzX).
  • Use ScheduleTask() for high-frequency updates.
  • Use RegisterCronJob() for periodic, non-frequent updates.
  • Specify a CycleRate for finer control over execution speed.
  • Use [Cycle] on methods to send to the engine periodically.

By leveraging these scheduling mechanisms, Altruist provides an efficient, scalable way to manage game server updates.