The player has the option to create a schedule, and later tell the AI engineer to execute it.
- Download Scheduler-VERSION.zip from the releases page
- Install with Railloader
- Connect Air
- Move
- Notice Wait
- Release handbrakes
- Restore switches
- Set handbrake
- Set switch
- Uncouple
- Wait
Connect air on train.
Move train
Parameter | Description |
---|---|
Direction | Move direction (forward / backward) |
AutoEngineerMode | Yard / Road mode |
MaxRoadSpeed | Max. speed when in road mode |
StopMode | Stop behavior |
- CarLengths: Train will travel N car lengths before stopping.
Shows notice to player and wait until player dismiss it.
Parameter | Description |
---|---|
Message | Message shown as notification to player. |
Release all handbrakes on train.
Restore state of switches, that where thrown by this schedule.
Sets handbrake on given car. Car index counted from locomotive.
Parameter | Description |
---|---|
CarIndex | Car index counted from locomotive. |
Save current switch state and set desired state.
Parameter | Description |
---|---|
Id | Node id of target switch. |
IsThrown | Desired state of switch (true=reversed, false=normal) |
Uncouple given car. Car index counted from locomotive.
Parameter | Description |
---|---|
CarIndex | Car index counted from locomotive. |
Wait given amount of milliseconds before continuing with next command in schedule.
Parameter | Description |
---|---|
MilliSeconds | Number of milliseconds to wait. |
In order to get going with this, follow the following steps:
- Clone the repo
- Copy the
Paths.user.example
toPaths.user
, open the newPaths.user
and set the<GameDir>
to your game's directory. - Open the Solution
- You're ready!
Make sure you're using the Debug configuration. Every time you build your project, the files will be copied to your Mods folder and you can immediately start the game to test it.
Make sure you're using the Release configuration. The build pipeline will then automatically do a few things:
- Makes sure it's a proper release build without debug symbols
- Replaces
$(AssemblyVersion)
in theDefinition.json
with the actual assembly version. - Copies all build outputs into a zip file inside
bin
with a ready-to-extract structure inside, named like the project they belonged to and the version of it.
- Create you own mod, that is referencing this one
- Implement
Scheduler.Utility.ICommand
interface - Inherd
Scheduler.Utility.CommandManager<TCommand>
class - Register command and manager class by calling
Scheduler.Utility.ScheduleCommands.Register<TCommand, TCommandManager>()
during mod initialization phase.
Implementation of 'Wait' command:
public sealed class Wait(float milliSeconds) : ICommand
{
// Text shown in Scheduler dialog
public string DisplayText => $"Wait for {MilliSeconds * 0.001f:0.###} seconds";
// Command parameter
public float MilliSeconds { get; } = milliSeconds;
}
public sealed class WaitManager : CommandManager<Wait>
{
// Execute this command
// state holds data, that can be pass between commands
// "schedule" Schedule Reference to entire schedule
// "locomotive" BaseLocomitive Reference to locomotive
// "wage" int Wage to engineer after schedule complated:
// "index" int Command index in schedule
// "stop" bool? If set to true, schedule execution will be aborted
public override IEnumerator Execute(Dictionary<string, object> state) {
return new WaitForSecondsRealtime(Command!.MilliSeconds);
}
private float? _MilliSeconds;
// Serialize command parameter(s) to json
public override void SerializeProperties(JsonWriter writer) {
writer.WritePropertyName(nameof(Wait.MilliSeconds));
writer.WriteValue(Command!.MilliSeconds);
}
// Read json property to temporary field
protected override void ReadProperty(string propertyName, JsonReader reader, JsonSerializer serializer) {
if (propertyName == nameof(Wait.MilliSeconds)) {
_MilliSeconds = serializer.Deserialize<float>(reader);
}
}
// Verify, that mandatory properties where loaded via ReadProperty
// and create command
protected override object TryCreateCommand() {
if (_MilliSeconds == null) {
return "Missing mandatory property 'MilliSeconds'.";
}
return new Wait(_MilliSeconds!.Value);
}
// UI used in Schedule dialog when player configure command
public override void BuildPanel(UIPanelBuilder builder, BaseLocomotive locomotive) {
builder.AddField("Milliseconds", builder.AddSlider(() => _MilliSeconds ?? 0, () => (_MilliSeconds ?? 0).ToString("0"), o => _MilliSeconds = o, 0, 60 * 60 * 1000, true, o => _MilliSeconds = o)!);
}
}
// Command registration during plugin initialziation:
ScheduleCommands.Register<Wait, WaitManager>();