The Scheduler itself
🚪 The Scheduler
is our entry point into the API- it's our Wardrobe, our Doors of Durin,
our Ellis Island.
We saw some basic usage in the Overview, but now let's really get into it.
Scheduler opmode methods​
Scheduler.launch 🚀🚀🚀​
Scheduler.launch
is what starts the entire Scheduler system, and internally hosts the loop that
drives our OpModes.
() -> {}
- Java
- Kotlin
@Override
public void runOpMode() throws InterruptedException {
instantiateListeners();
waitForStart();
Scheduler.launch(this);
// or
Scheduler.launch(this, () -> {
// Loop code, such as PIDs
// Run at the end of every loop
});
}
override fun runOpMode() {
instantiateListeners()
waitForStart()
Scheduler.launch(this)
// or
Scheduler.launch(this) {
// Loop code, such as PIDs
// Run at the end of every loop
}
}
Scheduler.launchOnStart​
Equivalent to waitForStart(); Scheduler.launch(...);
Convenient for when you aren't doing anything on a loop during initialization until the game starts.
() -> {}
- Java
- Kotlin
@Override
public void runOpMode() throws InterruptedException {
instantiateListeners();
Scheduler.launchOnStart(this); // Waits until the opMode starts to launch
// or
Scheduler.launchOnStart(this, () -> {
// Loop code, such as PIDs
// Run at the end of every loop
});
}
override fun runOpMode() {
instantiateListeners()
Scheduler.launchOnStart(this) // Waits until the opMode starts to launch
// or
Scheduler.launchOnStart(this) {
// Loop code, such as PIDs
// Run at the end of every loop
}
}
Scheduler.launchManually​
Manually launches the Scheduler using the given lambda which returns a boolean, stopping when it returns false.
Has all the same functionality of Scheduler.launch()
- Java
- Kotlin
@Override
public void runOpMode() throws InterruptedException {
// Using int[] b/c of Java's effectively final thing
final int[] counter = { 1 };
// Could just pass it in directly too if you want
Function0<Boolean> condition = () -> counter[0] <= 3;
Scheduler.launchManually(condition, () -> { // Prints '123' then stops
System.out.print(counter[0]);
counter[0]++;
});
// Eqiv. to Scheduler.launch
Scheduler.launchManually(() -> opModeIsActive() && !isStopRequested());
}
override fun runOpMode() {
var counter = 1
Scheduler.launchManually({ counter <= 3 }) { // Prints '123' then stops
print(counter)
counter++
}
// Eqiv. to Scheduler.launch
Scheduler.launchManually({ opModeIsActive() && !isStopRequested })
}
Scheduler.beforeEach​
Runs a block of code before all the Listeners and the afterEach
block (the one passed directly into Scheduler.launch
runs).
- Java
- Kotlin
@Override
public void runOpMode() throws InterruptedException {
Listener.always(() -> { // Listener that runs every loop, called by static method
System.out.print(2);
});
Scheduler.beforeEach(() -> { // Runs at the start of every loop
System.out.print(1);
});
Scheduler.launch(this, () -> { // Prints '123' every loop
System.out.print(3);
});
}
override fun runOpMode() {
// Listener that runs every loop, called by static method
Listener.always { print(2) }
// Runs at the start of every loop
Scheduler.beforeEach { print(1) }
// Prints '123' every loop
Scheduler.launch(this) { print(3) }
}
Scheduler.debug​
Utility method for to help benchmark performance or debug Scheduler-related issues
It's also like Scheduler.launchManually
in that you need to explicitly pass in the loop condition
(scroll up if you need to read the documentation for that method for this to make sense)
The 'afterEach' block now takes in a SchedulerDebugInfo that contains some debug information. The class definition is as follows:
class SchedulerDebugInfo(
val loopTime: Double, /* raw loop time, not averaged */
val numHookedListeners: Int,
val numUniqueMessageSubs: Int,
)
Keep in mind Blacksmith may internally subscribe to a few messages or something akin.
() -> {}
- Java
- Kotlin
@Override
public void runOpMode() throws InterruptedException {
instantiateListeners();
waitForStart();
Scheduler.debug(() -> opModeIsActive() && !isStopRequested(), info -> {
telemetry.addData("LoopTime (ms)", info.getLoopTime());
telemetry.addData("Number of hooked listeners", info.getNumHookedListeners());
telemetry.addData("Number of (unique) msg subscribers", info.getNumUniqueMessageSubs());
telemetry.update();
});
}
override fun runOpMode() {
instantiateListeners()
waitForStart()
// Lambda w/ receiver ofc
Scheduler.debug({ opModeIsActive() && !isStopRequested }) {
telemetry.addData("LoopTime (ms)", loopTime)
telemetry.addData("Number of hooked listeners", numHookedListeners)
telemetry.addData("Number of (unique) msg subscribers", numUniqueMessageSubs)
telemetry.update()
}
}
Scheduler messaging methods​
A more niche functionality of the Scheduler is to directly send "messages" to invoke actions from the message receivers.
It can be triggered among classes and doesn't have to be used in an OpMode; it's versatile and can be used anywhere, even without a running OpMode.
Just be careful that your messages don't get mixed up and accidentally intercepted/interfere with each other.
- Java
- Kotlin
// The message can be anything you want
// Just make sure it's comparable in some way, as it uses .equals() internally
Scheduler.on("message", () -> {
System.out.print("Hello,");
});
Scheduler.on("message", () -> {
System.out.print(" world!");
});
Scheduler.emit("message"); // "Hello, world!" is printed
Scheduler.emit("message"); // "Hello, world!" is printed again
Object msg = new Object()
Scheduler.emit(msg); // Nothing happens, no one is listening for it
// The message can be anything you want
// Just make sure it's comparable in some way, as it uses .equals() internally
Scheduler.on("message") {
print("Hello,")
}
Scheduler.on("message") {
print(" world!")
}
Scheduler.emit("message") // "Hello, world!" is printed
Scheduler.emit("message") // "Hello, world!" is printed again
val msg = Any()
Scheduler.emit(msg) // Nothing happens, no one is listening for it
Scheduler.emit​
Broadcasts a message for anyone to receive with Scheduler.emit.
Scheduler.on​
Registers a message receiver, which will be called whenever a message is sent with Scheduler.emit.
Other Scheduler methods​
Scheduler.nuke​
Goes nuclear.
Destroys everything Scheduler API related.
Clears and unhooks all of the listeners, clears all of the messages, clears the beforeEach block.
Basically just a hard reset. But with a cooler name. Thanks GHCup.
you can still reuse all the listeners and stuff by just resubscribing actions to them
Optionally, if you want to only nuke specific parts of the Scheduler, you can pass in Nuke.Schedulables
,
Nuke.Messages
, or Nuke.BeforeEach
(you can pass in multiple as well since it's varargs)
Nuking the 'Schedulables' means nuking things that implement/use Schedulable, including listeners, timers, Ons, pulsars, gamepad listeners, etc.
- Java
- Kotlin
@Override
public void runOpMode() throws InterruptedException {
Scheduler.beforeEach(() -> System.out.println("Hi!"));
Listener(() -> true).whileHigh(() -> System.out.println("I'm high!"));
Scheduler.on("message", () -> ...)
Scheduler.nuke() // Nukes everything
// Scheduler.beforeEach == () -> {}
// Scheduler.listeners.size == 0
// Scheduler.messages.size == 0
Scheduler.nuke(Nuke.Schedulables) // Only nukes the listeners & other schedulables
// (also you can static import for readability)
Scheduler.nuke(Schedulables, BeforeEach) // Nukes everything besides messages
}
override fun runOpMode() {
Scheduler.beforeEach { println("Hi!") }
Listener { true }.whileHigh { println("I'm high!") }
Scheduler.on("message") {}
Scheduler.nuke() // Nukes everything
// Scheduler.beforeEach == () -> {}
// Scheduler.listeners.size == 0
// Scheduler.messages.size == 0
Scheduler.nuke(Listeners) // Only nukes the listeners
Scheduler.nuke(Listeners, BeforeEach) // Nukes everything besides messages
}
Nuke.All