diff --git a/.gitignore b/.gitignore index 6db6833..54c4c44 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ target/ Cargo.lock proto/StarRail.proto +/*.json \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 62034bb..7b056d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["common", "gameserver", "proto", "sdkserver", "xtask"] +members = ["common", "dispatch", "gameserver", "proto", "sdkserver", "xtask"] resolver = "2" [workspace.package] @@ -15,6 +15,8 @@ axum = "0.7.4" axum-server = "0.6.0" tower = "0.4.13" tower-http = { version = "0.5.2", features = ["normalize-path"] } +hyper = { version = "1.3.0", features = [ "client" ] } +hyper-util = { version = "0.1.3", features = [ "client-legacy" ] } dirs = "5.0.1" dotenv = "0.15.0" diff --git a/README.md b/README.md index 35c9344..1500e92 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,9 @@ A Server emulator for the game [`Honkai: Star Rail`](https://hsr.hoyoverse.com/e ```sh git clone https://git.xeondev.com/reversedrooms/AcheronSR.git cd AcheronSR -cargo install --path gameserver -cargo install --path sdkserver +cargo build --bin gameserver +cargo build --bin dispatch +cargo build --bin sdkserver ``` ##### Using xtasks (use this if stupid) @@ -43,23 +44,18 @@ page and download the latest release for your platform. To begin using the server, you need to run both the SDK server and the game server. -If you installed from source, Rust's installer should have added .cargo/bin to your -path, so simply run the following: - -```sh -gameserver -sdkserver -``` - If you installed from pre-built binaries, navigate to the directory where you downloaded the binaries and either a) double-click on the following executable names or b) run the following in a terminal: ```sh ./gameserver +./dispatch ./sdkserver ``` +##### Note: the `assets` folder should be in the same directory with the `gameserver`, otherwise it will panic. + ## Connecting [Get 2.2 beta client](https://bhrpg-prod.oss-accelerate.aliyuncs.com/client/beta/20240322124944_scfGE0xJXlWtoJ1r/StarRail_2.1.51.zip), diff --git a/common/Cargo.toml b/common/Cargo.toml index 071924a..6a5952f 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -4,6 +4,9 @@ edition = "2021" version.workspace = true [dependencies] +anyhow.workspace = true +ansi_term.workspace = true +env_logger.workspace = true tracing.workspace = true lazy_static.workspace = true serde.workspace = true diff --git a/common/src/lib.rs b/common/src/lib.rs index 5b85385..1e8bad6 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,2 +1,3 @@ pub mod data; +pub mod logging; pub mod util; diff --git a/gameserver/src/logging.rs b/common/src/logging.rs similarity index 100% rename from gameserver/src/logging.rs rename to common/src/logging.rs diff --git a/common/src/util.rs b/common/src/util.rs index d3a7a26..685ebdd 100644 --- a/common/src/util.rs +++ b/common/src/util.rs @@ -1,8 +1,9 @@ pub fn load_or_create_config(path: &str, defaults: &str) -> String { - if let Ok(data) = std::fs::read_to_string(path) { - data - } else { - std::fs::write(path, defaults).unwrap(); - defaults.to_string() - } + std::fs::read_to_string(path).map_or_else( + |_| { + std::fs::write(path, defaults).unwrap(); + defaults.to_string() + }, + |data| data, + ) } diff --git a/dispatch/Cargo.toml b/dispatch/Cargo.toml new file mode 100644 index 0000000..f769e09 --- /dev/null +++ b/dispatch/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "dispatch" +edition = "2021" +version.workspace = true + +[dependencies] +common.workspace = true + +anyhow.workspace = true +env_logger.workspace = true + +axum.workspace = true +axum-server.workspace = true + +lazy_static.workspace = true + +serde.workspace = true +serde_json.workspace = true + +tokio.workspace = true +tokio-util.workspace = true + +tracing.workspace = true +tracing-futures.workspace = true +tracing-log.workspace = true +tracing-subscriber.workspace = true +tracing-bunyan-formatter.workspace = true +ansi_term.workspace = true + +prost.workspace = true +rbase64.workspace = true +proto.workspace = true +tower.workspace = true +tower-http.workspace = true diff --git a/dispatch/dispatch.json b/dispatch/dispatch.json new file mode 100644 index 0000000..eb85303 --- /dev/null +++ b/dispatch/dispatch.json @@ -0,0 +1,34 @@ +{ + "http_port": 21041, + "game_servers": { + "acheron_sr": { + "name": "AcheronSR", + "title": "AcheronSR", + "dispatch_url": "http://127.0.0.1:21041/query_gateway/acheron_sr", + "env_type": "2", + "gateserver_ip": "127.0.0.1", + "gateserver_port": 23301, + "gateserver_protocol": "Tcp" + } + }, + "versions": { + "CNBETAWin2.1.51": { + "asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_6744505_89b2f5dc973e", + "ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_6759713_b4e0e740f0da", + "lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_6755976_3c46d7c46e2c", + "lua_version": "6755976" + }, + "CNBETAWin2.1.52": { + "asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_6785106_15237df2ef89", + "ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_6787319_5f3f1dae4769", + "lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_6785460_26c4b6c61a8b", + "lua_version": "6785460" + }, + "CNBETAWin2.1.53": { + "asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_6828321_72f2df86102b", + "ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_6834225_44836493b261", + "lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_6828764_f749b48347fd", + "lua_version": "6828764" + } + } +} diff --git a/dispatch/src/config.rs b/dispatch/src/config.rs new file mode 100644 index 0000000..fafaa88 --- /dev/null +++ b/dispatch/src/config.rs @@ -0,0 +1,51 @@ +use std::collections::HashMap; + +use common::util::load_or_create_config; +use lazy_static::lazy_static; +use serde::Deserialize; +use serde_json::from_str; + +const DEFAULT_CONFIG: &str = include_str!("../dispatch.json"); + +pub fn init_config() { + let _configuration = &*CONFIGURATION; +} + +#[derive(Deserialize)] +pub struct DispatchServerConfiguration { + pub http_port: u16, + pub game_servers: HashMap, + pub versions: HashMap, +} + +#[derive(Deserialize)] +pub struct VersionConfig { + pub asset_bundle_url: String, + pub ex_resource_url: String, + pub lua_url: String, + pub lua_version: String, +} + +#[derive(Deserialize)] +pub struct GameServerConfig { + pub name: String, + pub title: String, + pub dispatch_url: String, + pub env_type: String, + pub gateserver_ip: String, + pub gateserver_port: u16, + pub gateserver_protocol: GatewayProtocolType, +} + +#[derive(Deserialize, Eq, PartialEq)] +pub enum GatewayProtocolType { + Tcp, + Kcp, +} + +lazy_static! { + pub static ref CONFIGURATION: DispatchServerConfiguration = { + let data = load_or_create_config("dispatch.json", DEFAULT_CONFIG); + from_str(&data).unwrap() + }; +} diff --git a/dispatch/src/handlers.rs b/dispatch/src/handlers.rs new file mode 100644 index 0000000..4be1b58 --- /dev/null +++ b/dispatch/src/handlers.rs @@ -0,0 +1,85 @@ +use crate::config::*; +use axum::extract::{Path, Query}; +use prost::Message; +use proto::{Dispatch, Gateserver, RegionInfo}; +use serde::Deserialize; + +pub const QUERY_DISPATCH_PATH: &str = "/query_dispatch"; +pub const QUERY_GATEWAY_PATH: &str = "/query_gateway/:region_name"; + +#[tracing::instrument] +pub async fn query_dispatch() -> String { + let rsp = Dispatch { + retcode: 0, + region_list: CONFIGURATION + .game_servers + .iter() + .map(|(_, c)| RegionInfo { + name: c.name.clone(), + title: c.title.clone(), + env_type: c.env_type.clone(), + dispatch_url: c.dispatch_url.clone(), + ..Default::default() + }) + .collect(), + ..Default::default() + }; + + let mut buff = Vec::new(); + rsp.encode(&mut buff).unwrap(); + + rbase64::encode(&buff) +} + +#[derive(Deserialize, Debug)] +pub struct QueryGatewayParameters { + pub version: String, +} + +#[tracing::instrument] +pub async fn query_gateway( + Path(region_name): Path, + parameters: Query, +) -> String { + let rsp = if let Some(server_config) = CONFIGURATION.game_servers.get(®ion_name) { + if let Some(version_config) = CONFIGURATION.versions.get(¶meters.version) { + Gateserver { + retcode: 0, + ip: server_config.gateserver_ip.clone(), + port: server_config.gateserver_port as u32, + asset_bundle_url: version_config.asset_bundle_url.clone(), + ex_resource_url: version_config.ex_resource_url.clone(), + lua_url: version_config.lua_url.clone(), + lua_version: version_config.lua_version.clone(), + ifix_version: String::from("0"), + jblkncaoiao: true, + hjdjakjkdbi: true, + ldknmcpffim: true, + feehapamfci: true, + eebfeohfpph: true, + dfmjjcfhfea: true, + najikcgjgan: true, + giddjofkndm: true, + use_tcp: server_config.gateserver_protocol == GatewayProtocolType::Tcp, + ..Default::default() + } + } else { + Gateserver { + retcode: 9, + msg: format!("forbidden version: {} or invalid bind", parameters.version), + ..Default::default() + } + } + } else { + Gateserver { + retcode: 9, + msg: format!("server config for {region_name} not found"), + ..Default::default() + } + }; + + let mut buff = Vec::new(); + rsp.encode(&mut buff).unwrap(); + + rbase64::encode(&buff) +} diff --git a/dispatch/src/main.rs b/dispatch/src/main.rs new file mode 100644 index 0000000..be4a12f --- /dev/null +++ b/dispatch/src/main.rs @@ -0,0 +1,35 @@ +use anyhow::Result; +use axum::{extract::Request, routing::get, Router, ServiceExt}; +use common::logging::init_tracing; +use tokio::net::TcpListener; +use tower::Layer; +use tower_http::normalize_path::NormalizePathLayer; +use tracing::Level; + +mod config; +mod handlers; + +use config::{init_config, CONFIGURATION}; + +#[tokio::main] +async fn main() -> Result<()> { + init_tracing(); + init_config(); + + let span = tracing::span!(Level::DEBUG, "main"); + let _ = span.enter(); + + let app = Router::new() + .route(handlers::QUERY_DISPATCH_PATH, get(handlers::query_dispatch)) + .route(handlers::QUERY_GATEWAY_PATH, get(handlers::query_gateway)); + + let app = NormalizePathLayer::trim_trailing_slash().layer(app); + + let addr = format!("0.0.0.0:{}", CONFIGURATION.http_port); + let server = TcpListener::bind(&addr).await?; + + tracing::info!("dispatch is listening at {addr}"); + axum::serve(server, ServiceExt::::into_make_service(app)).await?; + + Ok(()) +} diff --git a/gameserver/src/main.rs b/gameserver/src/main.rs index 95ae3d9..af43eb0 100644 --- a/gameserver/src/main.rs +++ b/gameserver/src/main.rs @@ -1,13 +1,12 @@ use anyhow::Result; mod game; -mod logging; mod net; mod util; use common::data::init_assets; +use common::logging::init_tracing; use game::init_config; -use logging::init_tracing; #[tokio::main] async fn main() -> Result<()> { diff --git a/gameserver/src/net/gateway.rs b/gameserver/src/net/gateway.rs index 5120555..857272e 100644 --- a/gameserver/src/net/gateway.rs +++ b/gameserver/src/net/gateway.rs @@ -1,8 +1,9 @@ use anyhow::Result; +use common::log_error; use tokio::net::TcpListener; use tracing::{info_span, Instrument}; -use crate::{log_error, net::PlayerSession}; +use crate::net::PlayerSession; pub async fn listen(host: &str, port: u16) -> Result<()> { let listener = TcpListener::bind(format!("{host}:{port}")).await?; diff --git a/sdkserver/Cargo.toml b/sdkserver/Cargo.toml index 72a13ce..4d70926 100644 --- a/sdkserver/Cargo.toml +++ b/sdkserver/Cargo.toml @@ -11,6 +11,8 @@ env_logger.workspace = true axum.workspace = true axum-server.workspace = true +hyper.workspace = true +hyper-util.workspace = true dirs.workspace = true dotenv.workspace = true @@ -30,8 +32,6 @@ tracing-subscriber.workspace = true tracing-bunyan-formatter.workspace = true ansi_term.workspace = true -prost.workspace = true -rbase64.workspace = true -proto.workspace = true tower.workspace = true tower-http.workspace = true + diff --git a/sdkserver/sdkserver.json b/sdkserver/sdkserver.json new file mode 100644 index 0000000..685afa1 --- /dev/null +++ b/sdkserver/sdkserver.json @@ -0,0 +1,4 @@ +{ + "http_port": 21000, + "dispatch_endpoint": "http://127.0.0.1:21041" +} diff --git a/sdkserver/src/config.rs b/sdkserver/src/config.rs new file mode 100644 index 0000000..30e3ebc --- /dev/null +++ b/sdkserver/src/config.rs @@ -0,0 +1,23 @@ +use common::util::load_or_create_config; +use lazy_static::lazy_static; +use serde::Deserialize; +use serde_json::from_str; + +const DEFAULT_CONFIG: &str = include_str!("../sdkserver.json"); + +pub fn init_config() { + let _configuration = &*CONFIGURATION; +} + +#[derive(Deserialize)] +pub struct SDKServerConfiguration { + pub http_port: u16, + pub dispatch_endpoint: String, +} + +lazy_static! { + pub static ref CONFIGURATION: SDKServerConfiguration = { + let data = load_or_create_config("sdkserver.json", DEFAULT_CONFIG); + from_str(&data).unwrap() + }; +} diff --git a/sdkserver/src/config/mod.rs b/sdkserver/src/config/mod.rs deleted file mode 100644 index 8a2fcdd..0000000 --- a/sdkserver/src/config/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod version_config; - -pub use version_config::INSTANCE as versions; - -pub fn init_config() { - tracing::info!("loaded {} version configs", versions.len()); -} diff --git a/sdkserver/src/config/version_config.rs b/sdkserver/src/config/version_config.rs deleted file mode 100644 index a0003f7..0000000 --- a/sdkserver/src/config/version_config.rs +++ /dev/null @@ -1,23 +0,0 @@ -use std::collections::HashMap; - -use common::util::load_or_create_config; -use lazy_static::lazy_static; -use serde::Deserialize; -use serde_json::from_str; - -const DEFAULT_VERSIONS: &str = include_str!("../../versions.json"); - -#[derive(Deserialize)] -pub struct VersionConfig { - pub asset_bundle_url: String, - pub ex_resource_url: String, - pub lua_url: String, - pub lua_version: String, -} - -lazy_static! { - pub static ref INSTANCE: HashMap = { - let data = load_or_create_config("versions.json", DEFAULT_VERSIONS); - from_str(&data).unwrap() - }; -} diff --git a/sdkserver/src/logging.rs b/sdkserver/src/logging.rs deleted file mode 100644 index 1bfb6cc..0000000 --- a/sdkserver/src/logging.rs +++ /dev/null @@ -1,29 +0,0 @@ -#[macro_export] -macro_rules! log_error { - ($e:expr) => { - if let Err(e) = $e { - tracing::error!(error.message = %format!("{}", &e), "{:?}", e); - } - }; - ($context:expr, $e:expr $(,)?) => { - if let Err(e) = $e { - let e = format!("{:?}", ::anyhow::anyhow!(e).context($context)); - tracing::error!(error.message = %format!("{}", &e), "{:?}", e); - } - }; - ($ok_context:expr, $err_context:expr, $e:expr $(,)?) => { - if let Err(e) = $e { - let e = format!("{:?}", ::anyhow::anyhow!(e).context($err_context)); - tracing::error!(error.message = %format!("{}", &e), "{:?}", e); - } else { - tracing::info!($ok_context); - } - }; -} - -pub fn init_tracing() { - #[cfg(target_os = "windows")] - ansi_term::enable_ansi_support().unwrap(); - - env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); -} diff --git a/sdkserver/src/main.rs b/sdkserver/src/main.rs index 52e1699..c16fcf6 100644 --- a/sdkserver/src/main.rs +++ b/sdkserver/src/main.rs @@ -1,21 +1,24 @@ use anyhow::Result; +use axum::body::Body; use axum::extract::Request; use axum::routing::{get, post}; use axum::{Router, ServiceExt}; -use services::{auth, dispatch, errors}; +use hyper_util::{client::legacy::connect::HttpConnector, rt::TokioExecutor}; +use services::{auth, errors}; use tokio::net::TcpListener; use tower::Layer; use tower_http::normalize_path::NormalizePathLayer; use tracing::Level; +type Client = hyper_util::client::legacy::Client; + mod config; -mod logging; mod services; -use config::init_config; -use logging::init_tracing; +use common::logging::init_tracing; -const PORT: u16 = 21000; +use config::{init_config, CONFIGURATION}; +use services::reverse_proxy; #[tokio::main] async fn main() -> Result<()> { @@ -25,14 +28,16 @@ async fn main() -> Result<()> { let span = tracing::span!(Level::DEBUG, "main"); let _ = span.enter(); + // For dispatch reverse proxy + let client: Client = + hyper_util::client::legacy::Client::<(), ()>::builder(TokioExecutor::new()) + .build(HttpConnector::new()); + let app = Router::new() + .route("/query_dispatch", get(reverse_proxy::forward_to_dispatch)) .route( - dispatch::QUERY_DISPATCH_ENDPOINT, - get(dispatch::query_dispatch), - ) - .route( - dispatch::QUERY_GATEWAY_ENDPOINT, - get(dispatch::query_gateway), + "/query_gateway/:region_name", + get(reverse_proxy::forward_to_dispatch), ) .route(auth::RISKY_API_CHECK_ENDPOINT, post(auth::risky_api_check)) .route( @@ -47,11 +52,12 @@ async fn main() -> Result<()> { auth::GRANTER_LOGIN_VERIFICATION_ENDPOINT, post(auth::granter_login_verification), ) - .fallback(errors::not_found); + .fallback(errors::not_found) + .with_state(client); let app = NormalizePathLayer::trim_trailing_slash().layer(app); - let addr = format!("0.0.0.0:{PORT}"); + let addr = format!("0.0.0.0:{}", CONFIGURATION.http_port); let server = TcpListener::bind(&addr).await?; tracing::info!("sdkserver is listening at {addr}"); diff --git a/sdkserver/src/services/dispatch.rs b/sdkserver/src/services/dispatch.rs deleted file mode 100644 index 50aa520..0000000 --- a/sdkserver/src/services/dispatch.rs +++ /dev/null @@ -1,75 +0,0 @@ -use crate::config::versions; -use axum::extract::Query; -use prost::Message; -use proto::{Dispatch, Gateserver, RegionInfo}; -use serde::Deserialize; - -pub const QUERY_DISPATCH_ENDPOINT: &str = "/query_dispatch"; -pub const QUERY_GATEWAY_ENDPOINT: &str = "/query_gateway"; - -#[tracing::instrument] -pub async fn query_dispatch() -> String { - let rsp = Dispatch { - retcode: 0, - region_list: vec![RegionInfo { - name: String::from("AcheronSR"), - title: String::from("AcheronSR"), - env_type: String::from("2"), - dispatch_url: String::from("http://127.0.0.1:21000/query_gateway"), - ..Default::default() - }], - ..Default::default() - }; - - let mut buff = Vec::new(); - rsp.encode(&mut buff).unwrap(); - - rbase64::encode(&buff) -} - -#[derive(Deserialize, Debug)] -pub struct QueryGatewayParameters { - pub version: String, -} - -#[tracing::instrument] -pub async fn query_gateway(parameters: Query) -> String { - let rsp = if let Some(config) = versions.get(¶meters.version) { - Gateserver { - retcode: 0, - ip: String::from("127.0.0.1"), - port: 23301, - asset_bundle_url: config.asset_bundle_url.clone(), - ex_resource_url: config.ex_resource_url.clone(), - lua_url: config.lua_url.clone(), - lua_version: config.lua_version.clone(), - ifix_version: String::from("0"), - jblkncaoiao: true, - hjdjakjkdbi: true, - ldknmcpffim: true, - feehapamfci: true, - eebfeohfpph: true, - dfmjjcfhfea: true, - najikcgjgan: true, - giddjofkndm: true, - fbnbbembcgn: false, - dedgfjhbnok: false, - use_tcp: true, - linlaijbboh: false, - ahmbfbkhmgh: false, - nmdccehcdcc: false, - ..Default::default() - } - } else { - Gateserver { - retcode: 9, - msg: format!("forbidden version: {} or invalid bind", parameters.version), - ..Default::default() - } - }; - - let mut buff = Vec::new(); - rsp.encode(&mut buff).unwrap(); - - rbase64::encode(&buff) -} diff --git a/sdkserver/src/services/mod.rs b/sdkserver/src/services/mod.rs index 94c9403..0a5a45c 100644 --- a/sdkserver/src/services/mod.rs +++ b/sdkserver/src/services/mod.rs @@ -1,3 +1,3 @@ pub mod auth; -pub mod dispatch; pub mod errors; +pub mod reverse_proxy; diff --git a/sdkserver/src/services/reverse_proxy.rs b/sdkserver/src/services/reverse_proxy.rs new file mode 100644 index 0000000..0704407 --- /dev/null +++ b/sdkserver/src/services/reverse_proxy.rs @@ -0,0 +1,33 @@ +use axum::{ + body::Body, + extract::{Request, State}, + http::uri::{PathAndQuery, Uri}, + response::{IntoResponse, Response}, +}; +use hyper::StatusCode; +use hyper_util::client::legacy::connect::HttpConnector; + +use crate::config::CONFIGURATION; + +type Client = hyper_util::client::legacy::Client; + +pub async fn forward_to_dispatch( + State(client): State, + mut req: Request, +) -> Result { + let path = req.uri().path(); + let path_query = req + .uri() + .path_and_query() + .map_or(path, PathAndQuery::as_str); + + let uri = format!("{}{}", CONFIGURATION.dispatch_endpoint, path_query); + + *req.uri_mut() = Uri::try_from(uri).unwrap(); + + Ok(client + .request(req) + .await + .map_err(|_| StatusCode::BAD_REQUEST)? + .into_response()) +} diff --git a/sdkserver/versions.json b/sdkserver/versions.json deleted file mode 100644 index 8de71f9..0000000 --- a/sdkserver/versions.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "CNBETAWin2.1.51": { - "asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_6744505_89b2f5dc973e", - "ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_6759713_b4e0e740f0da", - "lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_6755976_3c46d7c46e2c", - "lua_version": "6755976" - }, - "CNBETAWin2.1.52": { - "asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_6785106_15237df2ef89", - "ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_6787319_5f3f1dae4769", - "lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_6785460_26c4b6c61a8b", - "lua_version": "6785460" - }, - "CNBETAWin2.1.53": { - "asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_6828321_72f2df86102b", - "ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_6834225_44836493b261", - "lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_6828764_f749b48347fd", - "lua_version": "6828764" - } -} diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 3ea8253..8bbfca1 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -36,6 +36,7 @@ fn spawn_servers(release: bool) -> Result<(), Box> { Ok::<(), io::Error>(()) }); + let tx2 = tx.clone(); let handle2 = thread::spawn(move || { let mut sdkserver = Command::new("cargo") .arg("run") @@ -46,6 +47,21 @@ fn spawn_servers(release: bool) -> Result<(), Box> { .expect("failed to start sdkserver"); let _ = sdkserver.wait()?; + tx2.send(()).expect("failed to send completion signal"); + + Ok::<(), io::Error>(()) + }); + + let handle3 = thread::spawn(move || { + let mut dispatch = Command::new("cargo") + .arg("run") + .arg("--bin") + .arg("dispatch") + .args(if release { vec!["--release"] } else { vec![] }) + .spawn() + .expect("failed to start dispatch"); + + let _ = dispatch.wait()?; tx.send(()).expect("failed to send completion signal"); Ok::<(), io::Error>(()) @@ -55,6 +71,7 @@ fn spawn_servers(release: bool) -> Result<(), Box> { handle1.join().expect("failed to join gameserver thread")?; handle2.join().expect("failed to join sdkserver thread")?; + handle3.join().expect("failed to join dispatch thread")?; Ok(()) }