Elemental is a Rust workspace for building Minecraft launchers.
It currently provides the pieces needed for a practical vanilla-launch workflow:
- Mojang protocol schemas in
elemental-schema - version resolution and launch metadata handling in
elemental-core - artifact downloading in
elemental-infra - Java runtime discovery from local providers
- an executable demo that downloads a version and launches it offline
crates/schema: Pure protocol and serialization typescrates/core: Launcher domain logic, Mojang services, storage, runtime lookup, launch buildercrates/infra: Downloader and execution reportscrates/loader: Mod-loader metadata integrationscrates/object: Shared typed object poolcrates/shared: Versioned persisted config/profile utilitiescrates/elemental: Re-export facade cratecrates/demo: End-to-end example
If you just want to verify the current example inside this repository:
cargo run -p demoThe demo will:
- Resolve Mojang metadata for a vanilla version
- Download the client jar, libraries, assets, and logging config
- Extract native libraries
- Discover a local Java runtime
- Launch the game with an offline account
The default demo settings live in crates/demo/src/lib.rs.
This is the smallest end-to-end flow using the library crates directly.
[dependencies]
anyhow = "1"
tokio = { version = "1", features = ["macros", "process", "rt-multi-thread"] }
elemental-core = { path = "crates/core" }
elemental-infra = { path = "crates/infra" }use std::path::PathBuf;
use anyhow::{Context, Result};
use elemental_core::{
auth::authorizers::offline::OfflineAuthorizer,
launcher::builder::LaunchBuilder,
runtime::{distribution::Distribution, provider::all_providers},
services::mojang::MojangService,
storage::{game::GameStorage, layout::BaseLayout},
};
use elemental_infra::downloader::core::ElementalDownloader;
#[tokio::main]
async fn main() -> Result<()> {
let game_root = PathBuf::from(".minecraft");
let version_id = "1.16.5".to_owned();
let version_name = "MyGame-1.16.5".to_owned();
let storage = GameStorage::new(&game_root, BaseLayout);
let service = MojangService::default();
let resolved = service
.resolve_vanilla_version(&storage, version_id, version_name, BaseLayout)
.await
.context("resolve vanilla version failed")?;
let downloader = ElementalDownloader::with_config_default()
.context("create downloader failed")?;
let reports = downloader
.execute_planner(&resolved.planner())
.await
.context("download version artifacts failed")?;
println!("download reports: {reports:#?}");
resolved
.version
.extract_natives()
.context("extract natives failed")?;
let runtime = Distribution::from_providers::<Vec<_>>(all_providers())
.await
.into_iter()
.find(|distribution| {
distribution
.release
.as_ref()
.and_then(|release| release.jre_version.as_ref())
.is_some_and(|version| version.starts_with("1.8"))
})
.context("can't find a local Java runtime with version prefix 1.8")?;
let authorizer = OfflineAuthorizer {
username: "Player".to_owned(),
};
let mut child = LaunchBuilder::new(authorizer, runtime, resolved.version)
.set_username("Player".to_owned())
.launch()
.await
.context("launch game failed")?;
let exit_status = child.wait().await.context("wait for game failed")?;
println!("game exited with: {exit_status}");
Ok(())
}- This example assumes you already have a compatible local Java runtime.
all_providers()looks for Java in sources such as the Windows registry,PATH, package-manager locations, andJAVA_HOME.- The example uses
OfflineAuthorizeron purpose so the minimal flow stays easy to run. - If you want a complete runnable reference from this repository, crates/demo/src/lib.rs is the best starting point.
- DeepWiki: https://deepwiki.com/ElectronicWave/Elemental
- Codacy dashboard: https://app.codacy.com/gh/ElectronicWave/Elemental/dashboard