Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/crates/ @BattleDash
/crates/maxima_ui @headassbtw
12 changes: 2 additions & 10 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
[workspace]
resolver = "2"
members = [
"maxima-bootstrap",
"maxima-cli",
"maxima-lib",
"maxima-native",
"maxima-service",
"maxima-tui",
"maxima-ui",
"maxima-resources",
]
exclude = [ ".gitignore", ".github/*" ]
members = [ "crates/*" ]

[profile.release]
strip = true
Expand Down
21 changes: 11 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
# Maxima
# MAXIMA
## A free and open-source replacement for the EA Desktop Launcher
![Logo](images/1500x500.jpg)

> [!WARNING]
> Maxima is in beta. Parts of it may not be fully stable, and we're actively fixing bugs and adding features. Please create an [issue](https://github.com/ArmchairDevelopers/Maxima/issues) if you notice strange behavior.
> Maxima is in a very alpha state. Parts of it may not be fully stable, and we are actively fixing bugs and adding features. As such, we recommend backing up save files before using Maxima, just to be safe. Please create an [issue](https://github.com/ArmchairDevelopers/Maxima/issues) if you notice strange behavior.

Maxima is an open-source replacement for the EA Desktop/Origin game launcher, running natively on Linux and Windows, with MacOS support in progress.

Maxima itself is a library (`maxima-lib`), with povided CLI (`maxima-cli`), TUI (`maxima-tui`), and GUI (`maxima-ui`) frontends. Other launchers compatible with Maxima's license may implement it as a backend. It's used by our sister project, [KYBER](https://uplink.kyber.gg/news/features-overview).
Maxima itself is a server (`maxima_server`) accessed through a client (`maxima_lib`). This provides support for multiple simultaneous frontends, meaning you can, for example, run the CLI and GUI at the same time, and their states will be synced.

We, by default, provide CLI (`maxima_cli`), TUI (`maxima_tui`), and GUI (`maxima_ui`) frontends. Other launchers compatible with Maxima's license may implement it as a backend. It's used by our sister project, [KYBER](https://uplink.kyber.gg/news/features-overview).

![UI](images/UI.png)

Expand All @@ -22,8 +24,7 @@ Maxima itself is a library (`maxima-lib`), with povided CLI (`maxima-cli`), TUI
- Playing games installed with EA Desktop on Maxima + vice versa
- Displaying your in-game status to your friends, and viewing your friends' status'
- Locating games
- Running games under [wine-ge](https://github.com/GloriousEggroll/wine-ge-custom) on Linux/SteamDeck
- `wine-ge` is automatically installed, but base `wine` must already be installed on the system. We're looking into implementing [umu-launcher](https://github.com/Open-Wine-Components/umu-launcher) to fix this.
- Running games under wine ([umu-launcher](https://github.com/Open-Wine-Components/umu-launcher)) on Linux/SteamDeck

**In-Dev:**
- MacOS support
Expand All @@ -32,18 +33,18 @@ Maxima itself is a library (`maxima-lib`), with povided CLI (`maxima-cli`), TUI
**Planned:**
- Library documentation/examples
- Support for installing DLCs
- Full EA Desktop interopability. Games installed with EA Desktop already appear on Maxima, but to take it a step further we'd like the ability to, for example, start a download on EA Desktop and continue it on Maxima.
- Full EA Desktop interopability. Games installed with EA Desktop already appear on Maxima, but to take it a step further we'd like the ability to, for example, start a download on EA Desktop and continue it on Maxima
- Cleaner/Stabler downloader implementation
- Progressive/Selective installs
- Some games are able to start without being fully installed, and some games contain language-specific files.
- Some games are able to start without being fully installed, and some games contain language-specific files
- Support for the store (buying games)
- Friend Adding/Removing/Inviting
- Status setting; locked to "online" at the moment

**Unsupported:**
- Battlefield 3/4 are currently unsupported due to how battlelog does game launching. This is on our radar, but isn't a huge priority at the moment.
- Battlefield 3/4 are currently unsupported due to how battlelog does game launching. This is on our radar, but isn't a huge priority at the moment
- Please file an issue if you find more games that don't work
- Old games like Dead Space 2 and BFBC2 are unsupported due to being pre-"Download-In-Place" era games. They have a different manifest format which we need to make a parser for.
- Old games like Dead Space 2 and BFBC2 are unsupported due to being pre-"Download-In-Place" era games. They have a different manifest format which we need to make a parser for

# CLI Usage
`maxima-cli` standalone will launch an interactive CLI mode to install and launch games.
Expand All @@ -54,5 +55,5 @@ Maxima itself is a library (`maxima-lib`), with povided CLI (`maxima-cli`), TUI
It's the farthest you can get from the Origin.

## Maintainers:
- [Sean Kahler](https://github.com/BattleDash) (Lib, Bootstrap, Service)
- [Sean Kahler](https://github.com/BattleDash) (Server, Lib, Proto, Bootstrap)
- [Nick Whelan](https://github.com/headassbtw) (UI)
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[package]
name = "maxima-bootstrap"
name = "maxima_bootstrap"
description = "Maxima handler for custom EA protocols"
version = "0.1.0"
authors = ["Sean Kahler <sean@battleda.sh>"]
edition = "2021"

[dependencies]
maxima-lib = { path = "../maxima-lib" }
maxima = { path = "../maxima_lib" }
tokio = { version = "1.28.2", features = [
"full",
"rt",
Expand Down Expand Up @@ -38,7 +38,7 @@ windows-service = "0.6.0"
cacao = "0.3.2"

[build-dependencies]
maxima-resources = { path = "../maxima-resources" }
maxima_resources = { path = "../maxima_resources" }

[[bin]]
name = "maxima-bootstrap"
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
10 changes: 3 additions & 7 deletions maxima-cli/Cargo.toml → crates/maxima_cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[package]
name = "maxima-cli"
name = "maxima_cli"
version = "0.1.0"
authors = ["Sean Kahler <sean@battleda.sh>"]
edition = "2021"

[dependencies]
maxima-lib = { path = "../maxima-lib" }
maxima = { path = "../maxima_lib" }
clap = { version = "4.3.5", features = [ "derive" ] }
tokio = { version = "1.28.2", features = [ "full", "rt", "rt-multi-thread", "time", "net" ] }
serde = { version = "1.0.164", features = [ "derive" ] }
Expand All @@ -24,8 +24,4 @@ winreg = "0.50.0"
is_elevated = "0.1.2"

[build-dependencies]
maxima-resources = { path = "../maxima-resources" }

[[bin]]
name = "maxima-cli"
path = "src/main.rs"
maxima_resources = { path = "../maxima_resources" }
File renamed without changes.
File renamed without changes.
3 changes: 2 additions & 1 deletion maxima-lib/Cargo.toml → crates/maxima_lib/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "maxima-lib"
name = "maxima"
version = "1.0.0"
edition = "2021"
authors = ["Sean Kahler <sean@battleda.sh>"]
Expand All @@ -20,6 +20,7 @@ tokio = { version = "1.28.2", features = [
"time",
"net",
] }
maxima_proto = { path = "../maxima_proto" }
moka = { version = "0.12.1", features = ["sync"] }
serde = { version = "1.0.164", features = ["derive"] }
serde_json = "1.0.97"
Expand Down
3 changes: 3 additions & 0 deletions crates/maxima_lib/examples/dev.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {

}
1 change: 1 addition & 0 deletions crates/maxima_lib/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub use maxima_proto::models;
6 changes: 3 additions & 3 deletions maxima-native/Cargo.toml → crates/maxima_native/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[package]
name = "maxima-native"
name = "maxima_native"
version = "0.1.0"
authors = ["Sean Kahler <sean@battleda.sh>"]
edition = "2021"

[dependencies]
maxima-lib = { path = "../maxima-lib" }
maxima = { path = "../maxima_lib" }
tokio = { version = "1.28.2", features = [
"full",
"rt",
Expand Down Expand Up @@ -43,7 +43,7 @@ widestring = "1.0.2"
dll-syringe = "0.15.2"

[build-dependencies]
maxima-resources = { path = "../maxima-resources" }
maxima_resources = { path = "../maxima_resources" }
cbindgen = "0.25.0"

[lib]
Expand Down
149 changes: 149 additions & 0 deletions crates/maxima_native/bindings.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
#define ERR_SUCCESS 0

#define ERR_UNKNOWN 1

#define ERR_CHECK_LE 2

#define ERR_LOGIN_FAILED 3

#define ERR_INVALID_ARGUMENT 4

#define ERR_NOT_LOGGED_IN 5

/**
* Get the last error.
*/
const char *maxima_get_last_error(void);

/**
* Set up Maxima's logging.
*/
uintptr_t maxima_init_logger(void);

/**
* Create an asynchronous runtime.
*/
uintptr_t maxima_create_runtime(void **runtime_out);

/**
* Check if the Maxima Background Service is installed and valid.
*/
uintptr_t maxima_is_service_valid(bool *out);

/**
* Check if the Maxima Background Service is running.
*/
uintptr_t maxima_is_service_running(bool *out);

/**
* Register the Maxima Background Service. Runs maxima-bootstrap for admin access.
*/
uintptr_t maxima_register_service(void);

/**
* Start the Maxima Background Service.
*/
uintptr_t maxima_start_service(void **runtime);

/**
* Stop the Maxima Background Service.
*/
uintptr_t maxima_stop_service(void **runtime);

/**
* Check if the Windows Registry is properly set up for Maxima.
*/
bool maxima_check_registry_validity(void);

/**
* Request the Maxima Background Service to set up the Windows Registry.
*/
uintptr_t maxima_request_registry_setup(void **runtime);

/**
* Log into an EA account and retrieve an access token. Opens the EA website for authentication.
*/
uintptr_t maxima_login(void **runtime, char **token_out);

/**
* Log into an EA account with a persona (email/username) and password.
*/
uintptr_t maxima_login_manual(void **runtime, void **mx, const char *persona, const char *password);

/**
* Retrieve the access token for the currently selected account. Can return [ERR_NOT_LOGGED_IN]
*/
uintptr_t maxima_access_token(void **runtime, void **mx, const char **token_out);

/**
* Retrieve a nucleus auth code with the specified client id. Can return [ERR_NOT_LOGGED_IN]
*/
uintptr_t maxima_auth_exchange(void **runtime,
void **mx,
const char *client_id,
const char **code_out);

/**
* Create a Maxima object.
*/
const void *maxima_mx_create(void **runtime);

/**
* Set the stored token retrieved from [maxima_login].
*/
uintptr_t maxima_mx_set_access_token(void **runtime, const void **mx, const char *token);

/**
* Set the port to be used for the LSX server. This will be automatically passed to games.
* Note that not every game supports a custom LSX port, the default is 3216.
*/
void maxima_mx_set_lsx_port(void **runtime, const void **mx, unsigned short port);

/**
* Start the LSX server used for game communication.
*/
uintptr_t maxima_mx_start_lsx(void **runtime, const void **mx);

/**
* Consume pending LSX events.
*/
uintptr_t maxima_mx_consume_lsx_events(void **runtime,
const void **mx,
const char ***events_out,
unsigned int **event_pids_out,
unsigned int *event_count_out);

/**
* Free LSX events retrieved from [maxima_mx_consume_lsx_events].
*/
void maxima_mx_free_lsx_events(char **events, unsigned int event_count);

/**
* Launch a game with Maxima, providing an EA Offer ID.
*/
uintptr_t maxima_launch_game(void **runtime, const void **mx, const char *c_offer_id);

/**
* Find an owned game's offer ID by its slug.
*/
uintptr_t maxima_find_owned_offer(void **runtime,
const void **mx,
const char *c_game_slug,
const char **offer_id_out);

/**
* Get the local user's display name.
*/
uintptr_t maxima_get_local_display_name(void **runtime,
const void **mx,
const char **display_name_out);

/**
* Pull the application's window into the foreground.
*/
uintptr_t maxima_take_foreground_focus(void);

/**
* Read the path for an EA game.
*/
uintptr_t maxima_read_game_path(const char *c_name, const char **c_out_path);
File renamed without changes.
File renamed without changes.
File renamed without changes.
37 changes: 37 additions & 0 deletions crates/maxima_proto/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
[package]
name = "maxima_proto"
version = "1.0.0"
edition = "2021"
authors = ["Sean Kahler <sean@battleda.sh>"]
categories = ["games"]
description = "A free and open-source replacement for the EA Desktop Launcher"
keywords = ["electronic-arts", "linux-gaming"]
license = "GPL-3.0"
readme = "README.md"
repository = "https://github.com/ArmchairDevelopers/Maxima"
documentation = "https://docs.rs/maxima"
rust-version = "1.81.0"

[dependencies]
tokio = { version = "1.28.2", features = [
"full",
"rt",
"rt-multi-thread",
"time",
"net",
] }
serde = { version = "1.0.164", features = ["derive"] }
serde_json = "1.0.97"
paste = "1.0.12"
anyhow = "1.0.71"
derive-getters = "0.3.0"
derive_builder = "0.12.0"
rand = "0.8.5"
futures = "0.3.30"
bytes = "1.5.0"
async-trait = "0.1.81"
tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "json"] }
thiserror = "2.0.3"
const-fnv1a-hash = "1.1.0"
typed-builder = "0.20.0"
20 changes: 20 additions & 0 deletions crates/maxima_proto/examples/auth_check.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use maxima_proto::comp::{auth::CheckAuthRequest, util::IdentificationRequest};
use tracing::info;

mod entry;

#[tokio::main]
async fn main() {
let (_, component_man) = entry::client_setup::create_conn_man();

let req = IdentificationRequest::builder()
.client_id("Test".to_owned())
.version("Test".to_owned())
.build();

let _ = component_man.util().identify(req).await.expect("Failed to identify");

let req = CheckAuthRequest::builder().allow_cached(false).build();
let res = component_man.auth().check(req).await;
info!("Logged in?: {:#?}", res.unwrap());
}
17 changes: 17 additions & 0 deletions crates/maxima_proto/examples/client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use maxima_proto::comp::util::IdentificationRequest;
use tracing::info;

mod entry;

#[tokio::main]
async fn main() {
let (_, component_man) = entry::client_setup::create_conn_man();

let req = IdentificationRequest::builder()
.client_id("Test".to_owned())
.version("Test".to_owned())
.build();

let response = component_man.util().identify(req).await;
info!("Response: {:#?}", response.unwrap());
}
Loading