Expand description
A read-only, high-level, virtual file API for the RuneScape cache.
This crate provides high performant data reads into the Oldschool RuneScape and RuneScape 3 cache file systems. It can read the necessary data to synchronize the client’s cache with the server. There are also some loaders that give access to definitions from the cache such as items or npcs.
For read-heavy workloads, a writer can be used to prevent continuous buffer allocations. By default every read will allocate a writer with the correct capacity.
RuneScape’s chat system uses huffman coding to compress messages. In order to decompress them
this library has a Huffman implementation.
When a RuneScape client sends game packets the id’s are encoded and can be decoded with the
IsaacRand implementation. These id’s are encoded by the client in a predictable random order
which can be reversed if the server has its own IsaacRand with the same encoder/decoder keys.
These keys are sent by the client on login and are user specific. It will only send encoded
packet id’s if the packets are game packets.
Note that this crate is still evolving; both OSRS & RS3 are not fully supported/implemented and will probably contain bugs or miss core features. If you require features or find bugs consider opening an issue.
§Safety
In order to read bytes in a high performant way the cache uses memmap2. This can be unsafe because of its potential for Undefined Behaviour when the underlying file is subsequently modified, in or out of process.
Using Mmap here is safe because the RuneScape cache is a read-only binary file system. The map
will remain valid even after the File is dropped, it’s completely independent of the File
used to create it. Therefore, the use of unsafe is not propagated outwards. When the Cache is
dropped memory will be subsequently unmapped.
§Features
The cache’s protocol defaults to OSRS. In order to use the RS3 protocol you can enable the rs3
feature flag. A lot of types derive serde’s Serialize and Deserialize. The serde-derive
feature flag can be used to enable (de)serialization on any compatible types.
§Quick Start
The recommended usage would be to wrap it using
std::sync::LazyLock making it the
easiest way to access cache data from anywhere and at any time. No need for an Arc or a
Mutex because Cache will always be Send + Sync.
use rscache::Cache;
use std::sync::LazyLock;
static CACHE: LazyLock<Cache> = LazyLock::new(|| {
Cache::new("./data/osrs_cache")
.expect("cache files to be successfully memory mapped")
});
std::thread::spawn(|| -> Result<(), rscache::Error> {
let buffer = CACHE.read(0, 10)?;
Ok(())
});
std::thread::spawn(|| -> Result<(), rscache::Error> {
let buffer = CACHE.read(0, 10)?;
Ok(())
});For an instance that stays local to this thread you can simply use:
use rscache::Cache;
let cache = Cache::new("./data/osrs_cache")
.expect("cache files to be successfully memory mapped");
let index_id = 2; // Config index.
let archive_id = 10; // Archive containing item definitions.
let buffer = cache.read(index_id, archive_id)?;If you want to share the instance over multiple threads you can do so by wrapping it in an
Arc
use rscache::Cache;
use std::sync::Arc;
let cache = Arc::new(Cache::new("./data/osrs_cache")
.expect("cache files to be successfully memory mapped"));
let c = Arc::clone(&cache);
std::thread::spawn(move || -> Result<(), rscache::Error> {
// use the cloned handle
let buffer = c.read(0, 10)?;
Ok(())
});
std::thread::spawn(move || -> Result<(), rscache::Error> {
// use handle directly and take ownership
let buffer = cache.read(0, 10)?;
Ok(())
});§Loaders
In order to get definitions you can look at the loaders this library provides. The loaders use the cache as a dependency to parse in their data and cache the relevant definitions internally. The loader module also tells you how to make a loader if this crate doesn’t (yet) provide it.
Note: Some loaders cache these definitions lazily because of either the size of the data or the performance. The map loader for example is both slow and large so caching is by default lazy. Lazy loaders require mutability.
Modules§
- checksum
- Validator for the cache.
- definition
- Defines RuneScape data structures.
- error
- Error management.
- extension
- Extension traits.
- loader
- Loaders for definitions.
- util
- Helpful utility functions, macros and structs.
Structs§
- Cache
- A complete virtual representation of the RuneScape cache file system.
Enums§
- Error
- Super error type for all cache errors.