asr/
lib.rs

1#![no_std]
2#![warn(
3    clippy::complexity,
4    clippy::correctness,
5    clippy::perf,
6    clippy::style,
7    clippy::missing_const_for_fn,
8    clippy::undocumented_unsafe_blocks,
9    missing_docs,
10    rust_2018_idioms
11)]
12#![cfg_attr(doc_cfg, feature(doc_cfg))]
13
14//! Helper crate to write auto splitters for LiveSplit One's auto splitting
15//! runtime.
16//!
17//! There are two ways of defining an auto splitter.
18//!
19//! # Defining an `update` function
20//!
21//! You can define an `update` function that will be called every frame. This is
22//! the simplest way to define an auto splitter. The function must have the
23//! following signature:
24//! ```no_run
25//! #[no_mangle]
26//! pub extern "C" fn update() {}
27//! ```
28//!
29//! The advantage of this approach is that you have full control over what
30//! happens on every tick of the runtime. However, it's much harder to keep
31//! state around as you need to store all state in global variables as you need
32//! to return out of the function on every tick.
33//!
34//! ## Example
35//!
36//! ```no_run
37//! # use asr::Process;
38//! #[no_mangle]
39//! pub extern "C" fn update() {
40//!     if let Some(process) = Process::attach("explorer.exe") {
41//!         asr::print_message("Hello World!");
42//!         if let Ok(address) = process.get_module_address("explorer.exe") {
43//!             if let Ok(value) = process.read::<u32>(address) {
44//!                 if value > 0 {
45//!                     asr::timer::start();
46//!                 }
47//!             }
48//!         }
49//!     }
50//! }
51//! ```
52//!
53//! # Defining an asynchronous `main` function
54//!
55//! You can use the [`async_main`] macro to define an asynchronous `main`
56//! function.
57//!
58//! Similar to using an `update` function, it is important to constantly yield
59//! back to the runtime to communicate that the auto splitter is still alive.
60//! All asynchronous code that you await automatically yields back to the
61//! runtime. However, if you want to write synchronous code, such as the main
62//! loop handling of a process on every tick, you can use the
63//! [`next_tick`](future::next_tick) function to yield back to the runtime and
64//! continue on the next tick.
65//!
66//! The main low level abstraction is the [`retry`](future::retry) function,
67//! which wraps any code that you want to retry until it succeeds, yielding back
68//! to the runtime between each try.
69//!
70//! So if you wanted to attach to a Process you could for example write:
71//!
72//! ```no_run
73//! # use asr::{Process, future::retry};
74//! # async fn example() {
75//! let process = retry(|| Process::attach("MyGame.exe")).await;
76//! # }
77//! ```
78//!
79//! This will try to attach to the process every tick until it succeeds. This
80//! specific example is exactly how the [`Process::wait_attach`] method is
81//! implemented. So if you wanted to attach to any of multiple processes, you
82//! could for example write:
83//!
84//! ```no_run
85//! # use asr::{Process, future::retry};
86//! # async fn example() {
87//! let process = retry(|| {
88//!    ["a.exe", "b.exe"].into_iter().find_map(Process::attach)
89//! }).await;
90//! # }
91//! ```
92//!
93//! ## Example
94//!
95//! Here is a full example of how an auto splitter could look like using the
96//! [`async_main`] macro:
97//!
98//! Usage on stable Rust:
99//! ```ignore
100//! async_main!(stable);
101//! ```
102//!
103//! Usage on nightly Rust:
104//! ```ignore
105//! #![feature(type_alias_impl_trait, const_async_blocks)]
106//!
107//! async_main!(nightly);
108//! ```
109//!
110//! The asynchronous main function itself:
111//! ```ignore
112//! async fn main() {
113//!     // TODO: Set up some general state and settings.
114//!     loop {
115//!         let process = Process::wait_attach("explorer.exe").await;
116//!         process.until_closes(async {
117//!             // TODO: Load some initial information from the process.
118//!             loop {
119//!                 // TODO: Do something on every tick.
120//!                next_tick().await;
121//!             }
122//!         }).await;
123//!     }
124//! }
125//! ```
126
127#[cfg(feature = "alloc")]
128extern crate alloc;
129
130mod primitives;
131mod runtime;
132
133pub mod deep_pointer;
134pub mod emulator;
135#[macro_use]
136pub mod future;
137pub mod file_format;
138pub mod game_engine;
139#[cfg(feature = "signature")]
140pub mod signature;
141pub mod string;
142pub mod sync;
143pub mod time_util;
144#[cfg(all(feature = "wasi-no-std", target_os = "wasi"))]
145mod wasi_no_std;
146pub mod watcher;
147
148pub use self::{primitives::*, runtime::*};
149pub use arrayvec;
150pub use time;
151
152#[cfg(feature = "itoa")]
153pub use itoa;
154
155#[cfg(feature = "ryu")]
156pub use ryu;
157
158#[macro_use]
159mod panic;