Commands
Overview
This example demonstrates how to use Turbo Genesis command
and document
APIs to build a simple counter program with two commands: add
and reset
.
Creating Commands (Server)
The Counter document
#[turbo::os::document(program = "counter")]
pub struct Counter {
/// Current counter value
pub value: i32,
}
The add command
The add
command reads the counter
program file (creating it if it doesn't exist), updates the stored Counter
, increments its value, and writes it back.
use turbo::os::server::*;
#[turbo::os::command(program = "counter", name = "add")]
pub struct Add {
/// Amount to add to the counter
amount: i32,
}
impl CommandHandler for Add {
fn run(&mut self, user_id: &str) -> Result<(), std::io::Error> {
// Read existing counter or default to 0
let mut counter = fs::read("counter")
.unwrap_or(Counter { value: 0 });
// Apply increment
counter.value += self.amount;
log!("Incremented = {:?}", counter);
// Persist updated counter
fs::write("counter", &counter)?;
Ok(())
}
}
The reset command
The reset
command overwrites the counter
file with a Counter
initialized to 0
.
#[turbo::os::command(program = "counter", name = "reset")]
pub struct Reset;
impl CommandHandler for Reset {
fn run(&mut self, user_id: &str) -> Result<(), std::io::Error> {
// Overwrite the counter file with a Counter set to 0
fs::write("counter", &Counter { value: 0 })?;
Ok(())
}
}
Using Commands (Client)
Now let's use the commands to update the counter
document and display its value in the game.
Watch the Counter document
The counter data is stored in a program file named counter
.
#[turbo::game]
struct GameState;
impl GameState {
fn update(&mut self) {
// Watch the counter file and parse its contents when it loads
let counter = Counter::watch("counter")
.parse()
.unwrap_or(Counter { value: 0 });
// Draw the counter data
text!("{:#?}", counter);
}
}
Send some commands
Let's allow the player to add a random value or reset the counter file.
#[turbo::game]
struct GameState;
impl GameState {
fn update(&mut self) {
// Watch the counter file and parse its contents when it loads
let counter = Counter::watch("counter")
.parse()
.unwrap_or(Counter { value: 0 });
// Draw the counter data
text!("{:#?}", counter);
// When the "a" button (Z on keyboard) is pressed, send an Add command
if gamepad::get(0).a.just_pressed() {
let cmd = Add { amount: random::between(-100, 100) };
cmd.exec();
}
// When the "b" button (X on keyboard) is pressed, send a Reset command
if gamepad::get(0).b.just_pressed() {
let cmd = Reset;
cmd.exec();
}
}
}
Running your game
Review Your Code
Ensure that your src/lib.rs
file is correct:
See full src/lib.rs source code
use turbo::*;
use turbo::os::server::*;
#[turbo::os::document(program = "counter")]
pub struct Counter {
/// Current counter value
pub value: i32,
}
#[turbo::os::command(program = "counter", name = "add")]
pub struct Add {
/// Amount to add to the counter
amount: i32,
}
impl CommandHandler for Add {
fn run(&mut self, user_id: &str) -> Result<(), std::io::Error> {
// Read existing counter or default to 0
let mut counter = fs::read("counter")
.unwrap_or(Counter { value: 0 });
// Apply increment
counter.value += self.amount;
log!("Incremented = {:?}", counter);
// Persist updated counter
fs::write("counter", &counter)?;
Ok(())
}
}
#[turbo::os::command(program = "counter", name = "reset")]
pub struct Reset;
impl CommandHandler for Reset {
fn run(&mut self, user_id: &str) -> Result<(), std::io::Error> {
// Overwrite the counter file with a Counter set to 0
fs::write("counter", &Counter { value: 0 })?;
Ok(())
}
}
#[turbo::game]
struct GameState;
impl GameState {
fn update(&mut self) {
// Watch the counter file and parse its contents when it loads
let counter = Counter::watch("counter")
.parse()
.unwrap_or(Counter { value: 0 });
// Draw the counter data
text!("{:#?}", counter);
// When the "a" button (Z on keyboard) is pressed, send an Add command
if gamepad::get(0).a.just_pressed() {
let cmd = Add { amount: random::between(-100, 100) };
cmd.exec();
}
// When the "b" button (X on keyboard) is pressed, send a Reset command
if gamepad::get(0).b.just_pressed() {
let cmd = Reset;
cmd.exec();
}
}
}
Update your config
Update your turbo.toml
file to include the following section:
[turbo-os]
api-url = "https://os.turbo.computer"
Run with a user ID
Next, create a free dev account at https://os.turbo.computer. Your dashboard will display your user ID.
Run your game with:
turbo run -w --user <YOUR_USER_ID>
It will prompt you for a one-time password, which you'll find on your Turbo OS dashboard.
When your game launches, it will upload the program:
[turbo] Uploading "counter" (YOUR_PROGRAM_ID)...
[turbo] Uploaded "counter" (YOUR_PROGRAM_ID) β¨
Check your dashboard
On your Turbo OS Dashboard, scroll to the bottom to see uploaded programs. The counter
program will appear there.
Click the blue arrow to view the program analytics page:
As you send add
and reset
commands, you can inspect the live activity feed to see logs and how the commands were processed: