Compare commits
17 Commits
Author | SHA1 | Date | |
---|---|---|---|
7965314c6b | |||
cb70b8c415 | |||
79a1533eaa | |||
665e580c79 | |||
d5de7244e3 | |||
c2e90e17db | |||
c81518aec7 | |||
f48cd874f0 | |||
228abe5317 | |||
9efd34600a | |||
572c66cc16 | |||
cf87f7c741 | |||
dc8b01b4c8 | |||
9e8893ce75 | |||
6f92e1fb71 | |||
96c3e504f8 | |||
00c14d2a02 |
40
.github/workflows/lint.yml
vendored
40
.github/workflows/lint.yml
vendored
@ -1,9 +1,3 @@
|
|||||||
# Based on https://github.com/actions-rs/meta/blob/master/recipes/quickstart.md
|
|
||||||
#
|
|
||||||
# While our "example" application has the platform-specific code,
|
|
||||||
# for simplicity we are compiling and testing everything on the Ubuntu environment only.
|
|
||||||
# For multi-OS testing see the `cross.yml` workflow.
|
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
name: lint
|
name: lint
|
||||||
@ -14,18 +8,16 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install stable toolchain
|
- name: Install stable toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: dtolnay/rust-toolchain@stable
|
||||||
with:
|
with:
|
||||||
profile: minimal
|
|
||||||
toolchain: stable
|
toolchain: stable
|
||||||
override: true
|
|
||||||
|
|
||||||
- name: Run cargo check
|
- name: Run cargo check
|
||||||
uses: actions-rs/cargo@v1
|
uses: clechasseur/rs-cargo@v2
|
||||||
continue-on-error: true # WARNING: only for this example, remove it!
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
command: check
|
command: check
|
||||||
|
|
||||||
@ -34,18 +26,16 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install stable toolchain
|
- name: Install stable toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: dtolnay/rust-toolchain@stable
|
||||||
with:
|
with:
|
||||||
profile: minimal
|
|
||||||
toolchain: stable
|
toolchain: stable
|
||||||
override: true
|
|
||||||
|
|
||||||
- name: Run cargo test
|
- name: Run cargo test
|
||||||
uses: actions-rs/cargo@v1
|
uses: clechasseur/rs-cargo@v2
|
||||||
continue-on-error: true # WARNING: only for this example, remove it!
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
command: test
|
command: test
|
||||||
|
|
||||||
@ -54,26 +44,24 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install stable toolchain
|
- name: Install stable toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: dtolnay/rust-toolchain@stable
|
||||||
with:
|
with:
|
||||||
profile: minimal
|
|
||||||
toolchain: stable
|
toolchain: stable
|
||||||
override: true
|
|
||||||
components: rustfmt, clippy
|
components: rustfmt, clippy
|
||||||
|
|
||||||
- name: Run cargo fmt
|
- name: Run cargo fmt
|
||||||
uses: actions-rs/cargo@v1
|
uses: clechasseur/rs-cargo@v2
|
||||||
continue-on-error: true # WARNING: only for this example, remove it!
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
command: fmt
|
command: fmt
|
||||||
args: --all -- --check
|
args: --all -- --check
|
||||||
|
|
||||||
- name: Run cargo clippy
|
- name: Run cargo clippy
|
||||||
uses: actions-rs/cargo@v1
|
uses: clechasseur/rs-cargo@v2
|
||||||
continue-on-error: true # WARNING: only for this example, remove it!
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
command: clippy
|
command: clippy
|
||||||
args: -- -D warnings
|
args: -- -D warnings
|
||||||
|
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@ -9,7 +9,7 @@ jobs:
|
|||||||
create-release:
|
create-release:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- uses: taiki-e/create-gh-release-action@v1
|
- uses: taiki-e/create-gh-release-action@v1
|
||||||
with:
|
with:
|
||||||
draft: true
|
draft: true
|
||||||
@ -29,7 +29,7 @@ jobs:
|
|||||||
os: windows-latest
|
os: windows-latest
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- uses: taiki-e/upload-rust-binary-action@v1
|
- uses: taiki-e/upload-rust-binary-action@v1
|
||||||
with:
|
with:
|
||||||
target: ${{ matrix.target }}
|
target: ${{ matrix.target }}
|
||||||
|
110
Cargo.lock
generated
110
Cargo.lock
generated
@ -30,7 +30,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alterware-launcher"
|
name = "alterware-launcher"
|
||||||
version = "0.5.2"
|
version = "0.5.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"colored",
|
"colored",
|
||||||
"http_req",
|
"http_req",
|
||||||
@ -48,9 +48,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.13.1"
|
version = "0.21.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64ct"
|
name = "base64ct"
|
||||||
@ -312,11 +312,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http_req"
|
name = "http_req"
|
||||||
version = "0.9.3"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42ce34c74ec562d68f2c23a532c62c1332ff1d1b6147fd118bd1938e090137d0"
|
checksum = "158d4edacc70c9bdb0464314063b8d9d60fa776442dc13b00a13581b88b0a0a0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustls",
|
"rustls",
|
||||||
|
"rustls-pemfile",
|
||||||
"unicase",
|
"unicase",
|
||||||
"webpki",
|
"webpki",
|
||||||
"webpki-roots",
|
"webpki-roots",
|
||||||
@ -656,12 +657,26 @@ dependencies = [
|
|||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"spin",
|
"spin 0.5.2",
|
||||||
"untrusted",
|
"untrusted 0.7.1",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ring"
|
||||||
|
version = "0.17.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "911b295d2d302948838c8ac142da1ee09fa7863163b44e6715bc9357905878b8"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"getrandom",
|
||||||
|
"libc",
|
||||||
|
"spin 0.9.8",
|
||||||
|
"untrusted 0.9.0",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.8"
|
version = "0.38.8"
|
||||||
@ -677,15 +692,33 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls"
|
name = "rustls"
|
||||||
version = "0.19.1"
|
version = "0.21.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7"
|
checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"ring 0.16.20",
|
||||||
|
"rustls-webpki",
|
||||||
|
"sct",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-pemfile"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"log",
|
]
|
||||||
"ring",
|
|
||||||
"sct",
|
[[package]]
|
||||||
"webpki",
|
name = "rustls-webpki"
|
||||||
|
version = "0.101.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe"
|
||||||
|
dependencies = [
|
||||||
|
"ring 0.16.20",
|
||||||
|
"untrusted 0.7.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -696,12 +729,12 @@ checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sct"
|
name = "sct"
|
||||||
version = "0.6.1"
|
version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce"
|
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ring",
|
"ring 0.16.20",
|
||||||
"untrusted",
|
"untrusted 0.7.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -717,24 +750,24 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.19"
|
version = "1.0.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0"
|
checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.188"
|
version = "1.0.189"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
|
checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.188"
|
version = "1.0.189"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
|
checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -786,6 +819,12 @@ version = "0.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.9.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "steamlocate"
|
name = "steamlocate"
|
||||||
version = "2.0.0-alpha.0"
|
version = "2.0.0-alpha.0"
|
||||||
@ -889,9 +928,9 @@ checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicase"
|
name = "unicase"
|
||||||
version = "2.6.0"
|
version = "2.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
|
checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
@ -908,6 +947,12 @@ version = "0.7.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "untrusted"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
@ -986,22 +1031,19 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webpki"
|
name = "webpki"
|
||||||
version = "0.21.4"
|
version = "0.22.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea"
|
checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ring",
|
"ring 0.17.2",
|
||||||
"untrusted",
|
"untrusted 0.9.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webpki-roots"
|
name = "webpki-roots"
|
||||||
version = "0.21.1"
|
version = "0.25.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940"
|
checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc"
|
||||||
dependencies = [
|
|
||||||
"webpki",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "alterware-launcher"
|
name = "alterware-launcher"
|
||||||
version = "0.5.2"
|
version = "0.5.4"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
build = "res/build.rs"
|
build = "res/build.rs"
|
||||||
|
|
||||||
@ -15,14 +15,14 @@ panic = "abort"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
http_req = { version = "0.9.3", default-features = false, features = [
|
http_req = { version = "0.10.0", default-features = false, features = [
|
||||||
"rust-tls",
|
"rust-tls",
|
||||||
] }
|
] }
|
||||||
sha1_smol = "1.0.0"
|
sha1_smol = "1.0.0"
|
||||||
serde = { version = "1.0.188", features = ["derive"] }
|
serde = { version = "1.0.189", features = ["derive"] }
|
||||||
serde_json = "1.0.107"
|
serde_json = "1.0.107"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
semver = "1.0.19"
|
semver = "1.0.20"
|
||||||
zip = "0.6.6"
|
zip = "0.6.6"
|
||||||
colored = "2.0.4"
|
colored = "2.0.4"
|
||||||
|
|
||||||
|
25
README.md
25
README.md
@ -32,6 +32,7 @@
|
|||||||
- Do not include a trailing backslash in the path
|
- Do not include a trailing backslash in the path
|
||||||
- ```--pass```
|
- ```--pass```
|
||||||
- Pass additional arguments to the game
|
- Pass additional arguments to the game
|
||||||
|
- See [client-args.md](client-args.md)
|
||||||
- ```--version```, ```-v```
|
- ```--version```, ```-v```
|
||||||
- Print the launcher version
|
- Print the launcher version
|
||||||
|
|
||||||
@ -41,6 +42,30 @@ Some arguments can be set in alterware-launcher.json, args generally override th
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
#### Config file
|
||||||
|
alterware-launcher.json
|
||||||
|
|
||||||
|
- ```update_only```
|
||||||
|
- See --update
|
||||||
|
- Default: false
|
||||||
|
- ```skip_self_update```
|
||||||
|
- See --skip-launcher-update
|
||||||
|
- Default: false
|
||||||
|
- ```download_bonus_content```
|
||||||
|
- See --bonus
|
||||||
|
- Default: false
|
||||||
|
- ```ask_bonus_content```
|
||||||
|
- Ask the user if they want to download bonus content
|
||||||
|
- Default: true; false after asking
|
||||||
|
- ```force_update```
|
||||||
|
- See --force
|
||||||
|
- Default: false
|
||||||
|
- ```args```
|
||||||
|
- See --pass
|
||||||
|
- Default: ""
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
#### Support
|
#### Support
|
||||||
|
|
||||||
Visit the [AlterWare Forum](https://forum.alterware.dev/) or [Discord](https://discord.gg/2ETE8engZM) for support.
|
Visit the [AlterWare Forum](https://forum.alterware.dev/) or [Discord](https://discord.gg/2ETE8engZM) for support.
|
||||||
|
32
client-args.md
Normal file
32
client-args.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# IW4x
|
||||||
|
[github.com/iw4x/iw4x-client#command-line-arguments](https://github.com/iw4x/iw4x-client#command-line-arguments)
|
||||||
|
|
||||||
|
| Argument | Description |
|
||||||
|
|:------------------------|:-----------------------------------------------|
|
||||||
|
| `-tests` | Perform unit tests. |
|
||||||
|
| `-entries` | Print to the console a list of every asset as they are loaded from zonefiles. |
|
||||||
|
| `-stdout` | Redirect all logging output to the terminal iw4x is started from, or if there is none, creates a new terminal window to write log information in. |
|
||||||
|
| `-console` | Allow the game to display its own separate interactive console window. |
|
||||||
|
| `-dedicated` | Starts the game as a headless dedicated server. |
|
||||||
|
| `-bigminidumps` | Include all code sections from loaded modules in the dump. |
|
||||||
|
| `-reallybigminidumps` | Include data sections from all loaded modules in the dump. |
|
||||||
|
| `-dump` | Write info of loaded assets to the raw folder as they are being loaded. |
|
||||||
|
| `-nointro` | Skip game's cinematic intro. |
|
||||||
|
| `-version` | Print IW4x build info on startup. |
|
||||||
|
| `-nosteam` | Disable friends feature and do not update Steam about the game's current status just like an invisible mode. |
|
||||||
|
| `-unprotect-dvars` | Allow the server to modify saved/archive dvars. |
|
||||||
|
| `-zonebuilder` | Start the interactive zonebuilder tool console instead of starting the game. |
|
||||||
|
| `-disable-notifies` | Disable "Anti-CFG" checks |
|
||||||
|
| `-disable-mongoose` | Disable Mongoose HTTP server |
|
||||||
|
| `-disable-rate-limit-check` | Disable RCOn rate limit checks |
|
||||||
|
| `+<command>` | Execute game command (ex. `+set net_port 1337`)|
|
||||||
|
|
||||||
|
|
||||||
|
# S1-Mod, IW6-Mod
|
||||||
|
| Argument | Description |
|
||||||
|
|:------------------------|:-----------------------------------------------|
|
||||||
|
| `-headless` | Use system console |
|
||||||
|
| `-dedicated` | Dedicated server |
|
||||||
|
| `-singleplayer` | Start singleplayer; Skip launcher |
|
||||||
|
| `-multiplayer` | Start multiplayer; Skip launcher |
|
||||||
|
| `+<command>` | Execute game command (ex. `+set net_port 1337`)|
|
@ -13,7 +13,19 @@ pub fn load(config_path: PathBuf) -> Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn save(config_path: PathBuf, config: Config) {
|
pub fn save(config_path: PathBuf, config: Config) {
|
||||||
fs::write(config_path, serde_json::to_string_pretty(&config).unwrap()).unwrap();
|
match fs::write(
|
||||||
|
config_path.clone(),
|
||||||
|
serde_json::to_string_pretty(&config).unwrap(),
|
||||||
|
) {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(e) => match e.kind() {
|
||||||
|
std::io::ErrorKind::NotFound => {
|
||||||
|
fs::create_dir_all(config_path.parent().unwrap()).unwrap();
|
||||||
|
save(config_path, config);
|
||||||
|
}
|
||||||
|
_ => println!("Could not save config file, got:\n{}\n", e),
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_value(config_path: PathBuf, key: &str, value: bool) {
|
pub fn save_value(config_path: PathBuf, key: &str, value: bool) {
|
||||||
|
76
src/http.rs
76
src/http.rs
@ -1,20 +1,40 @@
|
|||||||
|
use crate::global;
|
||||||
|
use crate::misc;
|
||||||
use std::{fs, io::Write, path::Path, str};
|
use std::{fs, io::Write, path::Path, str};
|
||||||
|
|
||||||
pub fn get_body(url: &str) -> Vec<u8> {
|
pub fn get_body(url: &str) -> Vec<u8> {
|
||||||
let mut res: Vec<u8> = Vec::new();
|
let mut res: Vec<u8> = Vec::new();
|
||||||
let req = http_req::request::Request::new(&url.try_into().unwrap())
|
|
||||||
|
match http_req::request::Request::new(&url.try_into().unwrap())
|
||||||
.header(
|
.header(
|
||||||
"User-Agent",
|
"User-Agent",
|
||||||
"AlterWare Launcher | github.com/mxve/alterware-launcher",
|
&format!(
|
||||||
|
"AlterWare Launcher | github.com/{}/{}",
|
||||||
|
global::GH_OWNER,
|
||||||
|
global::GH_REPO
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.send(&mut res)
|
.send(&mut res)
|
||||||
.unwrap_or_else(|error| {
|
{
|
||||||
panic!("\n\n{}:\n{:?}", "Error", error);
|
Ok(req) => {
|
||||||
});
|
if req.status_code() == http_req::response::StatusCode::new(302)
|
||||||
|
|| req.status_code() == http_req::response::StatusCode::new(301)
|
||||||
|
{
|
||||||
|
let location = req.headers().get("Location").unwrap().as_str();
|
||||||
|
return get_body(location);
|
||||||
|
}
|
||||||
|
|
||||||
if req.status_code() == http_req::response::StatusCode::new(302) {
|
if req.status_code() != http_req::response::StatusCode::new(200) {
|
||||||
let location = req.headers().get("Location").unwrap().as_str();
|
misc::fatal_error(&format!(
|
||||||
return get_body(location);
|
"Could not get body from {}, got {}",
|
||||||
|
url,
|
||||||
|
req.status_code()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
misc::fatal_error(&format!("Could not get body from {}, got:\n{}", url, e));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res
|
res
|
||||||
@ -27,10 +47,38 @@ pub fn get_body_string(url: &str) -> String {
|
|||||||
pub fn download_file(url: &str, file_path: &Path) {
|
pub fn download_file(url: &str, file_path: &Path) {
|
||||||
let body = get_body(url);
|
let body = get_body(url);
|
||||||
|
|
||||||
let mut f = fs::File::create(file_path).unwrap_or_else(|error| {
|
match fs::File::create(file_path) {
|
||||||
panic!("\n\n{}:\n{:?}", "Error", error);
|
Ok(mut file) => match file.write_all(&body) {
|
||||||
});
|
Ok(_) => (),
|
||||||
f.write_all(&body).unwrap_or_else(|error| {
|
Err(e) => {
|
||||||
panic!("\n\n{}:\n{:?}", "Error", error);
|
misc::fatal_error(&format!(
|
||||||
});
|
"Could not write to file {}, got:\n{}",
|
||||||
|
file_path.to_str().unwrap(),
|
||||||
|
e
|
||||||
|
));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
match e.kind() {
|
||||||
|
std::io::ErrorKind::NotFound => {
|
||||||
|
fs::create_dir_all(file_path.parent().unwrap()).unwrap();
|
||||||
|
return download_file(url, file_path);
|
||||||
|
}
|
||||||
|
std::io::ErrorKind::PermissionDenied => {
|
||||||
|
misc::fatal_error(&format!(
|
||||||
|
"Permission to {} denied.\n Please try:\n 1. Running the launcher as administrator.\n 2. Manually deleting the last downloaded file.\n 3. If your game is in the program files directory try moving it to another location.\n 4. Create an exception/exclusion in your Anti-Virus Software for either the last downloaded file or the entire game directory.\n\n\n{}",
|
||||||
|
file_path.to_str().unwrap(),
|
||||||
|
e
|
||||||
|
));
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
misc::fatal_error(&format!(
|
||||||
|
"Could not create file {}, got:\n{}",
|
||||||
|
file_path.to_str().unwrap(),
|
||||||
|
e
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
114
src/main.rs
114
src/main.rs
@ -37,26 +37,35 @@ fn get_installed_games(games: &Vec<Game>) -> Vec<(u32, PathBuf)> {
|
|||||||
installed_games
|
installed_games
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn create_shortcut(path: &Path, target: &Path, icon: String, args: String) {
|
||||||
|
if let Ok(mut sl) = ShellLink::new(target) {
|
||||||
|
sl.set_arguments(Some(args));
|
||||||
|
sl.set_icon_location(Some(icon));
|
||||||
|
sl.create_lnk(path).unwrap_or_else(|error| {
|
||||||
|
println!("Error creating shortcut.\n{:#?}", error);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
println!("Error creating shortcut.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn setup_client_links(game: &Game, game_dir: &Path) {
|
fn setup_client_links(game: &Game, game_dir: &Path) {
|
||||||
if game.client.len() > 1 {
|
if game.client.len() > 1 {
|
||||||
println!("Multiple clients installed, use the shortcuts (launch-<client>.lnk in the game directory or on the desktop) to launch a specific client.");
|
println!("Multiple clients installed, use the shortcuts (launch-<client>.lnk in the game directory or on the desktop) to launch a specific client.");
|
||||||
}
|
}
|
||||||
|
|
||||||
let target = game_dir.join("alterware-launcher.exe");
|
|
||||||
|
|
||||||
for c in game.client.iter() {
|
for c in game.client.iter() {
|
||||||
let lnk = game_dir.join(format!("launch-{}.lnk", c));
|
create_shortcut(
|
||||||
|
&game_dir.join(format!("launch-{}.lnk", c)),
|
||||||
let mut sl = ShellLink::new(target.clone()).unwrap();
|
&game_dir.join("alterware-launcher.exe"),
|
||||||
sl.set_arguments(Some(c.to_string()));
|
|
||||||
sl.set_icon_location(Some(
|
|
||||||
game_dir
|
game_dir
|
||||||
.join(format!("{}.exe", c))
|
.join(format!("{}.exe", c))
|
||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.into_owned(),
|
.into_owned(),
|
||||||
));
|
c.to_string(),
|
||||||
sl.create_lnk(&lnk).unwrap();
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,19 +80,15 @@ fn setup_desktop_links(path: &Path, game: &Game) {
|
|||||||
std::env::var("USERPROFILE").unwrap()
|
std::env::var("USERPROFILE").unwrap()
|
||||||
));
|
));
|
||||||
|
|
||||||
let target = path.join("alterware-launcher.exe");
|
|
||||||
|
|
||||||
for c in game.client.iter() {
|
for c in game.client.iter() {
|
||||||
let lnk = desktop.join(format!("{}.lnk", c));
|
create_shortcut(
|
||||||
|
&desktop.join(format!("{}.lnk", c)),
|
||||||
let mut sl = ShellLink::new(target.clone()).unwrap();
|
&path.join("alterware-launcher.exe"),
|
||||||
sl.set_arguments(Some(c.to_string()));
|
|
||||||
sl.set_icon_location(Some(
|
|
||||||
path.join(format!("{}.exe", c))
|
path.join(format!("{}.exe", c))
|
||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.into_owned(),
|
.into_owned(),
|
||||||
));
|
c.to_string(),
|
||||||
sl.create_lnk(lnk).unwrap();
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,21 +180,35 @@ fn manual_install(games: &[Game]) {
|
|||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn total_download_size(cdn_info: &Vec<CdnFile>, remote_dir: &str) -> u64 {
|
||||||
|
let remote_dir = format!("{}/", remote_dir);
|
||||||
|
let mut size: u64 = 0;
|
||||||
|
for file in cdn_info {
|
||||||
|
if !file.name.starts_with(&remote_dir) || file.name == "iw4/iw4x.dll" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
size += file.size as u64;
|
||||||
|
}
|
||||||
|
size
|
||||||
|
}
|
||||||
|
|
||||||
fn update_dir(
|
fn update_dir(
|
||||||
cdn_info: &Vec<CdnFile>,
|
cdn_info: &Vec<CdnFile>,
|
||||||
remote_dir: &str,
|
remote_dir: &str,
|
||||||
dir: &Path,
|
dir: &Path,
|
||||||
hashes: &mut HashMap<String, String>,
|
hashes: &mut HashMap<String, String>,
|
||||||
) {
|
) {
|
||||||
let remote_dir = format!("{}/", remote_dir);
|
let remote_dir_pre = format!("{}/", remote_dir);
|
||||||
|
|
||||||
|
let mut files_to_download: Vec<CdnFile> = vec![];
|
||||||
|
|
||||||
for file in cdn_info {
|
for file in cdn_info {
|
||||||
if !file.name.starts_with(&remote_dir) || file.name == "iw4/iw4x.dll" {
|
if !file.name.starts_with(&remote_dir_pre) || file.name == "iw4/iw4x.dll" {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let sha1_remote = file.hash.to_lowercase();
|
let sha1_remote = file.hash.to_lowercase();
|
||||||
let file_name = &file.name.replace(remote_dir.as_str(), "");
|
let file_name = &file.name.replace(remote_dir_pre.as_str(), "");
|
||||||
let file_path = dir.join(file_name);
|
let file_path = dir.join(file_name);
|
||||||
if file_path.exists() {
|
if file_path.exists() {
|
||||||
let sha1_local = hashes
|
let sha1_local = hashes
|
||||||
@ -199,31 +218,46 @@ fn update_dir(
|
|||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
if sha1_local != sha1_remote {
|
if sha1_local != sha1_remote {
|
||||||
println!(
|
files_to_download.push(file.clone());
|
||||||
"[{}] {}",
|
|
||||||
"Updating".bright_yellow(),
|
|
||||||
file_path.display()
|
|
||||||
);
|
|
||||||
http::download_file(&format!("{}/{}", MASTER, file.name), &file_path);
|
|
||||||
} else {
|
} else {
|
||||||
println!("[{}] {}", "Checked".bright_blue(), file_path.display());
|
println!("[{}] {}", "Checked".bright_blue(), file_path.display());
|
||||||
}
|
}
|
||||||
hashes.insert(file_name.to_owned(), sha1_remote.to_owned());
|
|
||||||
} else {
|
} else {
|
||||||
println!(
|
files_to_download.push(file.clone());
|
||||||
"[{}] {}",
|
|
||||||
"Downloading".bright_yellow(),
|
|
||||||
file_path.display()
|
|
||||||
);
|
|
||||||
if let Some(parent) = file_path.parent() {
|
|
||||||
if !parent.exists() {
|
|
||||||
fs::create_dir_all(parent).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
http::download_file(&format!("{}/{}", MASTER, file.name), &file_path);
|
|
||||||
hashes.insert(file_name.to_owned(), sha1_remote.to_owned());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if files_to_download.is_empty() {
|
||||||
|
println!(
|
||||||
|
"[{}] No files to download for {}",
|
||||||
|
"Info".bright_magenta(),
|
||||||
|
remote_dir
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
println!(
|
||||||
|
"[{}] Downloading outdated or missing files for {}, {}",
|
||||||
|
"Info".bright_magenta(),
|
||||||
|
remote_dir,
|
||||||
|
misc::human_readable_bytes(total_download_size(&files_to_download, &remote_dir))
|
||||||
|
);
|
||||||
|
for file in files_to_download {
|
||||||
|
let file_name = &file.name.replace(&format!("{}/", remote_dir), "/");
|
||||||
|
let file_path = dir.join(file_name);
|
||||||
|
println!(
|
||||||
|
"[{}] {} ({})",
|
||||||
|
"Downloading".bright_yellow(),
|
||||||
|
file_path.display(),
|
||||||
|
misc::human_readable_bytes(file.size as u64)
|
||||||
|
);
|
||||||
|
if let Some(parent) = file_path.parent() {
|
||||||
|
if !parent.exists() {
|
||||||
|
fs::create_dir_all(parent).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
http::download_file(&format!("{}/{}", MASTER, file.name), &file_path);
|
||||||
|
hashes.insert(file_name.to_owned(), file.hash.to_lowercase());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(game: &Game, dir: &Path, bonus_content: bool, force: bool) {
|
fn update(game: &Game, dir: &Path, bonus_content: bool, force: bool) {
|
||||||
|
19
src/misc.rs
19
src/misc.rs
@ -1,5 +1,7 @@
|
|||||||
use std::{fs, path::PathBuf};
|
use std::{fs, path::PathBuf};
|
||||||
|
|
||||||
|
use colored::Colorize;
|
||||||
|
|
||||||
pub fn get_file_sha1(path: &PathBuf) -> String {
|
pub fn get_file_sha1(path: &PathBuf) -> String {
|
||||||
let mut sha1 = sha1_smol::Sha1::new();
|
let mut sha1 = sha1_smol::Sha1::new();
|
||||||
sha1.update(&fs::read(path).unwrap());
|
sha1.update(&fs::read(path).unwrap());
|
||||||
@ -18,3 +20,20 @@ pub fn rev_to_int(rev: &str) -> u16 {
|
|||||||
.parse::<u16>()
|
.parse::<u16>()
|
||||||
.unwrap_or(0)
|
.unwrap_or(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn fatal_error(error: &str) {
|
||||||
|
println!("\n\n{}:\n{}", "Error".bright_red(), error);
|
||||||
|
stdin();
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn human_readable_bytes(bytes: u64) -> String {
|
||||||
|
let mut bytes = bytes as f64;
|
||||||
|
let mut i = 0;
|
||||||
|
let units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||||
|
while bytes > 1024.0 {
|
||||||
|
bytes /= 1024.0;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
format!("{:.2} {}", bytes, units[i])
|
||||||
|
}
|
||||||
|
@ -30,6 +30,7 @@ pub fn run(update_only: bool) {
|
|||||||
use std::{fs, path::PathBuf};
|
use std::{fs, path::PathBuf};
|
||||||
|
|
||||||
use crate::http;
|
use crate::http;
|
||||||
|
use crate::misc;
|
||||||
|
|
||||||
let working_dir = std::env::current_dir().unwrap();
|
let working_dir = std::env::current_dir().unwrap();
|
||||||
let files = fs::read_dir(&working_dir).unwrap();
|
let files = fs::read_dir(&working_dir).unwrap();
|
||||||
@ -82,9 +83,13 @@ pub fn run(update_only: bool) {
|
|||||||
|
|
||||||
self_replace::self_replace("alterware-launcher-update.exe").unwrap();
|
self_replace::self_replace("alterware-launcher-update.exe").unwrap();
|
||||||
fs::remove_file(&file_path).unwrap();
|
fs::remove_file(&file_path).unwrap();
|
||||||
println!("Launcher updated. Please run it again.");
|
println!(
|
||||||
|
"Launcher updated. View the changelog at https://github.com/{}/{}/releases/latest",
|
||||||
|
GH_OWNER, GH_REPO,
|
||||||
|
);
|
||||||
|
println!("Please restart the launcher.");
|
||||||
if !update_only {
|
if !update_only {
|
||||||
std::io::stdin().read_line(&mut String::new()).unwrap();
|
misc::stdin();
|
||||||
}
|
}
|
||||||
std::process::exit(201);
|
std::process::exit(201);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#[derive(serde::Deserialize, serde::Serialize)]
|
#[derive(serde::Deserialize, serde::Serialize, Clone)]
|
||||||
pub struct CdnFile {
|
pub struct CdnFile {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub size: u32,
|
pub size: u32,
|
||||||
|
Reference in New Issue
Block a user