diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ab03990fc..ff35a48571 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -249,6 +249,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: dtolnay/rust-toolchain@stable + - run: rustup target add --toolchain stable wasm32-wasi - uses: actions/checkout@v3 - name: Rust cache uses: Leafwing-Studios/cargo-cache@v1.1.0 diff --git a/Cargo.lock b/Cargo.lock index b6176c49b9..ee2070072a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1065,6 +1065,7 @@ dependencies = [ "ambient_shared_types", "chrono", "convert_case 0.6.0", + "data-encoding", "indexmap 2.0.0", "once_cell", "paste", @@ -1074,6 +1075,7 @@ dependencies = [ "semver 1.0.18", "serde", "serde_json", + "sha2", "syn 1.0.109", "thiserror", "toml 0.7.8", diff --git a/app/src/cli/assets.rs b/app/src/cli/assets.rs index 14390fc4b3..203d9ff36f 100644 --- a/app/src/cli/assets.rs +++ b/app/src/cli/assets.rs @@ -1,12 +1,13 @@ -use std::path::PathBuf; +use std::path::{Path, PathBuf}; +use ambient_native_std::asset_cache::AssetCache; use anyhow::Context; use clap::{Args, Subcommand}; use super::PackagePath; #[derive(Subcommand, Clone, Debug)] -pub enum AssetCommand { +pub enum Assets { /// Migrate json pipelines to toml #[command(name = "migrate-pipelines-toml")] MigratePipelinesToml(MigrateOptions), @@ -17,14 +18,14 @@ pub enum AssetCommand { #[derive(Args, Clone, Debug)] pub struct MigrateOptions { - #[arg(index = 1, default_value = "./assets")] + #[arg(default_value = "./assets")] /// The path to the assets folder pub path: PathBuf, } #[derive(Args, Clone, Debug)] pub struct ImportOptions { - #[arg(index = 1)] + #[arg()] /// The path to the assets you want to import pub path: PathBuf, #[arg(long)] @@ -35,41 +36,45 @@ pub struct ImportOptions { pub collider_from_model: bool, } -pub async fn handle(command: &AssetCommand, assets: &crate::AssetCache) -> anyhow::Result<()> { +pub async fn handle(command: &Assets, assets: &AssetCache) -> anyhow::Result<()> { match command { - AssetCommand::MigratePipelinesToml(opt) => { - let path = PackagePath::new_local(opt.path.clone())?; - ambient_build::migrate::toml::process(path.fs_path.unwrap()) - .await - .context("Failed to migrate pipelines")?; + Assets::MigratePipelinesToml(opt) => { + migrate_pipelines_toml(opt).await?; } - AssetCommand::Import(opt) => match opt.path.extension() { - Some(ext) => { - if ext == "wav" || ext == "mp3" || ext == "ogg" { - let convert = opt.convert_audio; - ambient_build::pipelines::import_audio(opt.path.clone(), convert) - .context("Failed to import audio")?; - } else if ext == "fbx" || ext == "glb" || ext == "gltf" || ext == "obj" { - let collider_from_model = opt.collider_from_model; - ambient_build::pipelines::import_model(opt.path.clone(), collider_from_model) - .context("Failed to import models")?; - } else if ext == "jpg" || ext == "png" || ext == "gif" || ext == "webp" { - // TODO: import textures API may change, so this is just a placeholder - todo!(); - } else { - anyhow::bail!("Unsupported file type"); - } - ambient_build::build_assets( - assets, - &PathBuf::from("assets"), - &PathBuf::from("build"), - true, - ) - .await?; - } - None => anyhow::bail!("Unknown file type"), - }, + Assets::Import(opt) => import(opt, assets).await?, } Ok(()) } + +async fn migrate_pipelines_toml(opt: &MigrateOptions) -> Result<(), anyhow::Error> { + let path = PackagePath::new_local(opt.path.clone())?; + ambient_build::migrate::toml::process(path.fs_path.unwrap()) + .await + .context("Failed to migrate pipelines")?; + Ok(()) +} + +async fn import(opt: &ImportOptions, assets: &AssetCache) -> anyhow::Result<()> { + let Some(ext) = opt.path.extension() else { + anyhow::bail!("Unknown file type"); + }; + + if ext == "wav" || ext == "mp3" || ext == "ogg" { + let convert = opt.convert_audio; + ambient_build::pipelines::import_audio(opt.path.clone(), convert) + .context("Failed to import audio")?; + } else if ext == "fbx" || ext == "glb" || ext == "gltf" || ext == "obj" { + let collider_from_model = opt.collider_from_model; + ambient_build::pipelines::import_model(opt.path.clone(), collider_from_model) + .context("Failed to import models")?; + } else if ext == "jpg" || ext == "png" || ext == "gif" || ext == "webp" { + // TODO: import textures API may change, so this is just a placeholder + todo!(); + } else { + anyhow::bail!("Unsupported file type"); + } + ambient_build::build_assets(assets, Path::new("assets"), Path::new("build"), true).await?; + + Ok(()) +} diff --git a/app/src/cli/client.rs b/app/src/cli/client.rs deleted file mode 100644 index f5b911787a..0000000000 --- a/app/src/cli/client.rs +++ /dev/null @@ -1,45 +0,0 @@ -use std::path::PathBuf; - -use ambient_audio::AudioStream; -use ambient_core::window::ExitStatus; -use ambient_native_std::asset_cache::AssetCache; -use ambient_network::native::client::ResolvedAddr; - -use crate::client; - -use super::RunCli; - -pub fn handle( - run: &RunCli, - rt: &tokio::runtime::Runtime, - assets: AssetCache, - server_addr: ResolvedAddr, - golden_image_output_dir: Option, -) -> anyhow::Result<()> { - let audio_stream = if !run.mute_audio { - match AudioStream::new() { - Ok(v) => Some(v), - Err(err) => { - log::error!("Failed to initialize audio stream: {err}"); - None - } - } - } else { - None - }; - - let mixer = if run.mute_audio { - None - } else { - audio_stream.as_ref().map(|v| v.mixer().clone()) - }; - - // If we have run parameters, start a client and join a server - let exit_status = client::run(rt, assets, server_addr, run, golden_image_output_dir, mixer); - - if exit_status == ExitStatus::FAILURE { - anyhow::bail!("`client::run` failed with {exit_status:?}"); - } - - Ok(()) -} diff --git a/app/src/cli/join.rs b/app/src/cli/join.rs new file mode 100644 index 0000000000..2dfeea5c52 --- /dev/null +++ b/app/src/cli/join.rs @@ -0,0 +1,44 @@ +use ambient_native_std::{ + asset_cache::{AssetCache, SyncAssetKeyExt}, + download_asset::ReqwestClientKey, +}; +use ambient_network::native::client::ResolvedAddr; +use clap::Parser; + +use crate::{client, server::QUIC_INTERFACE_PORT}; + +use super::ClientCli; + +#[derive(Parser, Clone, Debug)] +/// Join a multiplayer session +pub struct Join { + #[command(flatten)] + pub client: ClientCli, + /// The server to connect to; defaults to localhost + pub host: Option, +} + +pub fn handle(args: &Join, rt: &tokio::runtime::Runtime, assets: AssetCache) -> anyhow::Result<()> { + let assets_ref = &assets; + let server_addr = rt.block_on(async move { + let Some(mut host) = args.host.as_ref().cloned() else { + return Ok(ResolvedAddr::localhost_with_port(QUIC_INTERFACE_PORT)); + }; + + if host.starts_with("http://") || host.starts_with("https://") { + tracing::info!("NOTE: Joining server by http url is still experimental and can be removed without warning."); + + let reqwest = &ReqwestClientKey.get(assets_ref); + host = reqwest.get(host).send().await?.text().await?; + + if host.is_empty() { + anyhow::bail!("Failed to resolve host"); + } + } + if !host.contains(':') { + host = format!("{host}:{QUIC_INTERFACE_PORT}"); + } + ResolvedAddr::lookup_host(&host).await + })?; + client::run(rt, assets, server_addr, &args.client, None) +} diff --git a/app/src/cli/mod.rs b/app/src/cli/mod.rs index 06d1c325be..3d4ac36538 100644 --- a/app/src/cli/mod.rs +++ b/app/src/cli/mod.rs @@ -1,20 +1,22 @@ -use std::{net::IpAddr, path::PathBuf}; +use std::path::PathBuf; use clap::{Args, Parser, Subcommand}; -pub mod new_package; - pub mod assets; -pub mod build; -pub mod client; -pub mod deploy; +pub mod join; pub mod login; -pub mod server; +pub mod package; mod package_path; pub use package_path::*; -use self::{assets::AssetCommand, new_package::NewPackageCli}; +use self::{ + assets::Assets, + join::Join, + package::{ + build::Build, deploy::Deploy, new::New, run::Run, serve::Serve, Package, PackageArgs, + }, +}; #[derive(Parser, Clone)] #[command(author, version, about, long_about = None)] @@ -26,80 +28,20 @@ pub struct Cli { #[derive(Parser, Clone, Debug)] pub enum Commands { - /// Create a new Ambient package - New { - #[command(flatten)] - package: PackageCli, - #[command(flatten)] - args: NewPackageCli, - }, - /// Builds and runs the package locally - Run { - #[command(flatten)] - package: PackageCli, - #[command(flatten)] - host: HostCli, - #[command(flatten)] - run: RunCli, - }, - /// View an asset - View { - #[command(flatten)] - package: PackageCli, - #[command(flatten)] - host: HostCli, - #[command(flatten)] - run: RunCli, - /// Relative to the package path - asset_path: PathBuf, - }, - /// Builds the package - Build { - #[command(flatten)] - package: PackageCli, - }, - /// Deploys the package - Deploy { - #[command(flatten)] - package: PackageCli, - /// Additional packages to deploy; this allows you to share deployed dependencies - /// between packages when doing a group deploy - #[arg(long)] - extra_packages: Vec, - /// API server endpoint - #[arg(long, default_value = ambient_shared_types::urls::API_URL)] - api_server: String, - /// Authentication token - #[arg(short, long)] - token: Option, - /// Don't use differential upload and upload all assets - #[arg(long)] - force_upload: bool, - /// Ensure the package is running after deploying - #[arg(long)] - ensure_running: bool, - /// Context to run the package in - #[arg(long, requires("ensure_running"), default_value = "")] - context: String, - }, - /// Builds and runs the package in server-only mode - Serve { - #[command(flatten)] - package: PackageCli, - #[command(flatten)] - host: HostCli, - }, - /// Join a multiplayer session - Join { - #[command(flatten)] - run: RunCli, - /// The server to connect to; defaults to localhost - host: Option, + New(New), + Run(Run), + Build(Build), + Deploy(Deploy), + Serve(Serve), + Join(Join), + Package { + #[command(subcommand)] + package: Package, }, /// Asset manipulation and migration Assets { #[command(subcommand)] - command: AssetCommand, + assets: Assets, }, /// Log into Ambient and save your API token to settings Login, @@ -122,7 +64,7 @@ pub enum GoldenImageCommand { } #[derive(Args, Clone, Debug)] -pub struct RunCli { +pub struct ClientCli { /// If set, show a debugger that can be used to investigate the state of the package. /// Can also be accessed through the `AMBIENT_DEBUGGER` environment variable #[arg(short, long)] @@ -172,119 +114,32 @@ pub struct RunCli { pub window_height: Option, } -#[derive(Args, Clone, Debug)] -pub struct PackageCli { - /// Dummy flag to catch Rust users using muscle memory and warn them - #[arg(long, short, hide = true)] - pub project: bool, - - /// The path or URL of the package to run; if not specified, this will default to the current directory - pub path: Option, - - /// Build all the assets with debug information; this will make them less performant and larger but easier to debug (default for all commands apart from `deploy` and `serve`) - #[arg(long, conflicts_with = "release")] - debug: bool, - - /// Build all the assets with full optimization; this will make them faster and smaller but more difficult to debug (default for `deploy` and `serve`) - #[arg(short, long)] - release: bool, - - /// Avoid building the package - #[arg(long)] - pub no_build: bool, - - #[arg(long)] - /// Perform a clean build - pub clean_build: bool, - - #[arg(long)] - /// Only build the WASM modules - pub build_wasm_only: bool, -} -impl PackageCli { - pub fn is_release(&self) -> Option { - match (self.debug, self.release) { - (true, false) => Some(false), - (false, true) => Some(true), - (false, false) => None, - (true, true) => { - // clap's conflict_with should prevent this from happening - panic!("debug and release are mutually exclusive") - } - } - } - - pub fn package_path(&self) -> anyhow::Result { - self.path.clone().try_into() - } -} - -#[derive(Args, Clone, Debug)] -pub struct HostCli { - #[arg(long, default_value = "0.0.0.0")] - pub bind_address: IpAddr, - /// Provide a public address or IP to the instance, which will allow users to connect to this instance over the internet - /// - /// Defaults to localhost - #[arg(long)] - pub public_host: Option, - - /// Defaults to 8889 - #[arg(long)] - pub http_interface_port: Option, - - /// Defaults to 9000 - #[arg(long)] - pub quic_interface_port: Option, - - /// Don't use proxy for NAT traversal - #[arg(long)] - pub no_proxy: bool, - - /// AmbientProxy address to use for NAT traversal - #[arg(long)] - pub proxy: Option, - - /// Pre-cache assets on the proxy - #[arg(long)] - pub proxy_pre_cache_assets: bool, - - /// Certificate for TLS - #[arg(long, requires("key"))] - pub cert: Option, - /// Private key for the certificate - #[arg(long)] - pub key: Option, - - /// Shutdown the server after the specified number of seconds of inactivity - #[arg(long)] - pub shutdown_after_inactivity_seconds: Option, -} - impl Cli { /// Extract package-relevant state only - pub fn package(&self) -> Option<&PackageCli> { + pub fn package(&self) -> Option<&PackageArgs> { match &self.command { - Commands::New { package, .. } => Some(package), - Commands::Run { package, .. } => Some(package), - Commands::Build { package, .. } => Some(package), - Commands::Deploy { package, .. } => Some(package), - Commands::Serve { package, .. } => Some(package), - Commands::View { package, .. } => Some(package), - Commands::Join { .. } => None, + Commands::Package { package } => Some(package.args()), + Commands::New(New { package, .. }) => Some(package), + Commands::Run(Run { package, .. }) => Some(package), + Commands::Build(Build { package, .. }) => Some(package), + Commands::Deploy(Deploy { package, .. }) => Some(package), + Commands::Serve(Serve { package, .. }) => Some(package), + Commands::Join(Join { .. }) => None, Commands::Assets { .. } => None, Commands::Login => None, } } pub fn use_release_build(&self) -> bool { - use Commands::*; + use Commands as C; match &self.command { - Deploy { package, .. } | Serve { package, .. } => package.is_release().unwrap_or(true), - Run { package, .. } | Build { package, .. } | View { package, .. } => { + C::Deploy(Deploy { package, .. }) | C::Serve(Serve { package, .. }) => { + package.is_release().unwrap_or(true) + } + C::Run(Run { package, .. }) | C::Build(Build { package, .. }) => { package.is_release().unwrap_or(false) } - New { .. } | Join { .. } | Assets { .. } | Login => false, + C::New(_) | C::Join(_) | C::Assets { .. } | C::Package { .. } | C::Login => false, } } } diff --git a/app/src/cli/build.rs b/app/src/cli/package/build.rs similarity index 91% rename from app/src/cli/build.rs rename to app/src/cli/package/build.rs index e7b6dfc55f..53b9fcfb07 100644 --- a/app/src/cli/build.rs +++ b/app/src/cli/package/build.rs @@ -1,5 +1,4 @@ -use std::path::PathBuf; -use std::{collections::HashSet, future::Future}; +use std::{collections::HashSet, future::Future, path::PathBuf}; use ambient_build::BuildResult; use ambient_native_std::{asset_cache::AssetCache, asset_url::AbsAssetUrl}; @@ -7,8 +6,16 @@ use ambient_package::BuildSettings; use ambient_package_semantic::RetrievableFile; use anyhow::Context; +use clap::Parser; -use super::PackageCli; +use super::PackageArgs; + +#[derive(Parser, Clone, Debug)] +/// Builds the package +pub struct Build { + #[command(flatten)] + pub package: PackageArgs, +} pub struct BuildDirectories { /// The location where all built packages are stored. Used for the HTTP host. @@ -29,7 +36,15 @@ impl BuildDirectories { } pub async fn handle( - package_cli: &PackageCli, + build: &Build, + assets: &AssetCache, + release_build: bool, +) -> anyhow::Result { + handle_inner(&build.package, assets, release_build).await +} + +pub async fn handle_inner( + package_cli: &PackageArgs, assets: &AssetCache, release_build: bool, ) -> anyhow::Result { @@ -50,7 +65,7 @@ pub async fn handle( let build_wasm_only = package_cli.build_wasm_only; let clean_build = package_cli.clean_build; - build( + self::build( assets, main_package_fs_path, clean_build, diff --git a/app/src/cli/deploy.rs b/app/src/cli/package/deploy.rs similarity index 84% rename from app/src/cli/deploy.rs rename to app/src/cli/package/deploy.rs index 4e52ee9a0b..4fee9eded1 100644 --- a/app/src/cli/deploy.rs +++ b/app/src/cli/package/deploy.rs @@ -4,24 +4,50 @@ use ambient_native_std::asset_cache::{AssetCache, SyncAssetKeyExt}; use ambient_package::Manifest; use ambient_settings::{Settings, SettingsKey}; use anyhow::Context; +use clap::Parser; use parking_lot::Mutex; -use crate::cli::build; - -use super::{PackageCli, PackagePath}; - -#[allow(clippy::too_many_arguments)] -pub async fn handle( - package: &PackageCli, - extra_packages: &[PathBuf], - assets: &AssetCache, - token: Option<&str>, - api_server: &str, - release_build: bool, - force_upload: bool, - ensure_running: bool, - context: &str, -) -> anyhow::Result<()> { +use crate::cli::{package::build, PackagePath}; + +use super::PackageArgs; + +#[derive(Parser, Clone, Debug)] +/// Deploys the package +pub struct Deploy { + #[command(flatten)] + pub package: PackageArgs, + /// Additional packages to deploy; this allows you to share deployed dependencies + /// between packages when doing a group deploy + #[arg(long)] + pub extra_packages: Vec, + /// API server endpoint + #[arg(long, default_value = ambient_shared_types::urls::API_URL)] + pub api_server: String, + /// Authentication token + #[arg(short, long)] + pub token: Option, + /// Don't use differential upload and upload all assets + #[arg(long)] + pub force_upload: bool, + /// Ensure the package is running after deploying + #[arg(long)] + pub ensure_running: bool, + /// Context to run the package in + #[arg(long, requires("ensure_running"), default_value = "")] + pub context: String, +} + +pub async fn handle(args: &Deploy, assets: &AssetCache, release_build: bool) -> anyhow::Result<()> { + let Deploy { + package, + extra_packages, + api_server, + token, + force_upload, + ensure_running, + context, + } = args; + if !release_build { // Using string interpolation due to a rustfmt bug where it will break // if any one line is too long @@ -152,9 +178,9 @@ pub async fn handle( let deployment = ambient_deploy::deploy( api_server, token, - build_path, - package_path, - force_upload, + &build_path, + &package_path, + *force_upload, ) .await?; Deployment::Deployed { @@ -204,7 +230,11 @@ pub async fn handle( let ensure_running_url = ambient_shared_types::urls::ensure_running_url(&deployment_id); let web_url = ambient_shared_types::urls::web_package_url( - manifest.package.id.as_str(), + manifest + .package + .id + .expect("no package ID - this is a bug") + .as_str(), Some(deployment_id.as_str()), ); @@ -222,7 +252,7 @@ pub async fn handle( } } - if let Some(deployment_id) = first_deployment_id.filter(|_| ensure_running) { + if let Some(deployment_id) = first_deployment_id.filter(|_| *ensure_running) { let spec = ambient_cloud_client::ServerSpec::new_with_deployment(deployment_id) .with_context(context.to_string()); let server = diff --git a/app/src/cli/package/mod.rs b/app/src/cli/package/mod.rs new file mode 100644 index 0000000000..f05d8a2206 --- /dev/null +++ b/app/src/cli/package/mod.rs @@ -0,0 +1,174 @@ +use std::{ + net::IpAddr, + path::{Path, PathBuf}, +}; + +use ambient_native_std::asset_cache::AssetCache; +use ambient_package::PackageId; +use anyhow::Context; +use clap::{Args, Subcommand}; + +use super::PackagePath; + +pub mod build; +pub mod deploy; +pub mod new; +pub mod run; +pub mod serve; + +#[derive(Subcommand, Clone, Debug)] +/// Package-related commands. +pub enum Package { + /// Regenerate the ID for a given package to make it compliant with the ID scheme. + RegenerateId { + #[command(flatten)] + package: PackageArgs, + }, +} +impl Package { + pub fn args(&self) -> &PackageArgs { + match self { + Package::RegenerateId { package } => package, + } + } +} + +#[derive(Args, Clone, Debug)] +pub struct PackageArgs { + /// Dummy flag to catch Rust users using muscle memory and warn them + #[arg(long, short, hide = true)] + pub project: bool, + + /// The path or URL of the package to run; if not specified, this will default to the current directory + pub path: Option, + + /// Build all the assets with debug information; this will make them less performant and larger but easier to debug (default for all commands apart from `deploy` and `serve`) + #[arg(long, conflicts_with = "release")] + debug: bool, + + /// Build all the assets with full optimization; this will make them faster and smaller but more difficult to debug (default for `deploy` and `serve`) + #[arg(short, long)] + release: bool, + + /// Avoid building the package + #[arg(long)] + pub no_build: bool, + + #[arg(long)] + /// Perform a clean build + pub clean_build: bool, + + #[arg(long)] + /// Only build the WASM modules + pub build_wasm_only: bool, +} +impl PackageArgs { + pub fn is_release(&self) -> Option { + match (self.debug, self.release) { + (true, false) => Some(false), + (false, true) => Some(true), + (false, false) => None, + (true, true) => { + // clap's conflict_with should prevent this from happening + panic!("debug and release are mutually exclusive") + } + } + } + + pub fn package_path(&self) -> anyhow::Result { + self.path.clone().try_into() + } +} + +#[derive(Args, Clone, Debug)] +pub struct HostCli { + #[arg(long, default_value = "0.0.0.0")] + pub bind_address: IpAddr, + /// Provide a public address or IP to the instance, which will allow users to connect to this instance over the internet + /// + /// Defaults to localhost + #[arg(long)] + pub public_host: Option, + + /// Defaults to 8889 + #[arg(long)] + pub http_interface_port: Option, + + /// Defaults to 9000 + #[arg(long)] + pub quic_interface_port: Option, + + /// Don't use proxy for NAT traversal + #[arg(long)] + pub no_proxy: bool, + + /// AmbientProxy address to use for NAT traversal + #[arg(long)] + pub proxy: Option, + + /// Pre-cache assets on the proxy + #[arg(long)] + pub proxy_pre_cache_assets: bool, + + /// Certificate for TLS + #[arg(long, requires("key"))] + pub cert: Option, + /// Private key for the certificate + #[arg(long)] + pub key: Option, + + /// Shutdown the server after the specified number of seconds of inactivity + #[arg(long)] + pub shutdown_after_inactivity_seconds: Option, +} + +pub fn handle( + args: &Package, + _rt: &tokio::runtime::Runtime, + _assets: AssetCache, +) -> anyhow::Result<()> { + match args { + Package::RegenerateId { package } => regenerate_id(package), + } +} + +fn regenerate_id(package: &PackageArgs) -> anyhow::Result<()> { + let package_path = package.package_path()?; + let Some(package_path) = &package_path.fs_path else { + anyhow::bail!("Cannot update ID of a remote package."); + }; + + let manifest_path = package_path.join("ambient.toml"); + if !manifest_path.is_file() { + anyhow::bail!("Package does not have a manifest"); + } + + update_id_for_manifest(&manifest_path)?; + + Ok(()) +} + +fn update_id_for_manifest(manifest_path: &Path) -> anyhow::Result<()> { + let mut toml = std::fs::read_to_string(&manifest_path)?.parse::()?; + // Only regenerate if an ID is already present + if toml + .get("package") + .and_then(|p| p.get("id")) + .is_some_and(|id| id.is_str()) + { + toml["package"]["id"] = toml_edit::value(PackageId::generate().to_string()); + } + + if let Some(includes) = toml.get("includes").and_then(|i| i.as_table_like()) { + for (include_name, include_path) in includes.iter() { + let include_path = include_path.as_str().with_context(|| { + format!("Invalid path for include `{include_name}` in {manifest_path:?}: {include_path:?}",) + })?; + + update_id_for_manifest(Path::new(include_path))?; + } + } + + std::fs::write(&manifest_path, toml.to_string())?; + Ok(()) +} diff --git a/app/src/cli/new_package.rs b/app/src/cli/package/new.rs similarity index 88% rename from app/src/cli/new_package.rs rename to app/src/cli/package/new.rs index 67f2ad0d9c..ac613b3b1d 100644 --- a/app/src/cli/new_package.rs +++ b/app/src/cli/package/new.rs @@ -1,22 +1,29 @@ use std::path::Path; -use ambient_native_std::ambient_version; +use ambient_native_std::{ambient_version, asset_cache::AssetCache}; use anyhow::Context; -use clap::{Args, ValueEnum}; +use clap::{Parser, ValueEnum}; use convert_case::{Case, Casing}; -use super::PackagePath; +use super::{build, PackageArgs}; + +#[derive(Parser, Clone, Debug)] +/// Create a new Ambient package +pub struct New { + #[command(flatten)] + pub package: PackageArgs, -#[derive(Args, Clone, Debug)] -pub struct NewPackageCli { #[arg(short, long)] name: Option, + #[arg(long)] api_path: Option, + /// This package is being created in an existing Rust workspace, /// and does not need to have extra files generated for it. #[arg(long)] in_workspace: bool, + #[arg(long, value_enum, default_value_t)] rust: RustTemplate, } @@ -32,7 +39,9 @@ pub enum RustTemplate { Quad, } -pub(crate) fn handle(package_path: &PackagePath, args: &NewPackageCli) -> anyhow::Result<()> { +pub(crate) async fn handle(args: &New, assets: &AssetCache) -> anyhow::Result<()> { + let package_path = args.package.package_path()?; + let Some(package_path) = &package_path.fs_path else { anyhow::bail!("Cannot create package in a remote directory."); }; @@ -141,13 +150,19 @@ pub(crate) fn handle(package_path: &PackagePath, args: &NewPackageCli) -> anyhow std::fs::write(&path, contents).with_context(|| format!("Failed to create {path:?}"))?; } - log::info!("Package \"{name}\" created at {package_path:?}"); + log::info!("Package \"{name}\" created; doing first build"); + + // Build the new package to ensure that the user can use it immediately, and to have the proc-macro + // ready for rust-analyzer to use + build::handle_inner(&args.package, &assets, false).await?; + + log::info!("Package \"{name}\" built successfully - ready to go at {package_path:?}"); Ok(()) } fn build_cargo_toml( - package_path: &std::path::Path, + package_path: &Path, api_path: Option<&str>, snake_case_name: String, ) -> String { diff --git a/app/src/cli/new_package_template/.cargo/config.toml b/app/src/cli/package/new_package_template/.cargo/config.toml similarity index 100% rename from app/src/cli/new_package_template/.cargo/config.toml rename to app/src/cli/package/new_package_template/.cargo/config.toml diff --git a/app/src/cli/new_package_template/.gitignore b/app/src/cli/package/new_package_template/.gitignore similarity index 100% rename from app/src/cli/new_package_template/.gitignore rename to app/src/cli/package/new_package_template/.gitignore diff --git a/app/src/cli/new_package_template/.vscode/extensions.json b/app/src/cli/package/new_package_template/.vscode/extensions.json similarity index 100% rename from app/src/cli/new_package_template/.vscode/extensions.json rename to app/src/cli/package/new_package_template/.vscode/extensions.json diff --git a/app/src/cli/new_package_template/.vscode/launch.json b/app/src/cli/package/new_package_template/.vscode/launch.json similarity index 100% rename from app/src/cli/new_package_template/.vscode/launch.json rename to app/src/cli/package/new_package_template/.vscode/launch.json diff --git a/app/src/cli/new_package_template/.vscode/settings.json b/app/src/cli/package/new_package_template/.vscode/settings.json similarity index 100% rename from app/src/cli/new_package_template/.vscode/settings.json rename to app/src/cli/package/new_package_template/.vscode/settings.json diff --git a/app/src/cli/new_package_template/Cargo.toml b/app/src/cli/package/new_package_template/Cargo.toml similarity index 100% rename from app/src/cli/new_package_template/Cargo.toml rename to app/src/cli/package/new_package_template/Cargo.toml diff --git a/app/src/cli/new_package_template/ambient.toml b/app/src/cli/package/new_package_template/ambient.toml similarity index 100% rename from app/src/cli/new_package_template/ambient.toml rename to app/src/cli/package/new_package_template/ambient.toml diff --git a/app/src/cli/new_package_template/rust-toolchain.toml b/app/src/cli/package/new_package_template/rust-toolchain.toml similarity index 100% rename from app/src/cli/new_package_template/rust-toolchain.toml rename to app/src/cli/package/new_package_template/rust-toolchain.toml diff --git a/app/src/cli/new_package_template/src/client.rs b/app/src/cli/package/new_package_template/src/client.rs similarity index 100% rename from app/src/cli/new_package_template/src/client.rs rename to app/src/cli/package/new_package_template/src/client.rs diff --git a/app/src/cli/new_package_template/src/server_empty.rs b/app/src/cli/package/new_package_template/src/server_empty.rs similarity index 100% rename from app/src/cli/new_package_template/src/server_empty.rs rename to app/src/cli/package/new_package_template/src/server_empty.rs diff --git a/app/src/cli/new_package_template/src/server_quad.rs b/app/src/cli/package/new_package_template/src/server_quad.rs similarity index 100% rename from app/src/cli/new_package_template/src/server_quad.rs rename to app/src/cli/package/new_package_template/src/server_quad.rs diff --git a/app/src/cli/package/run.rs b/app/src/cli/package/run.rs new file mode 100644 index 0000000000..c15ab99e01 --- /dev/null +++ b/app/src/cli/package/run.rs @@ -0,0 +1,40 @@ +use ambient_native_std::asset_cache::AssetCache; +use clap::Parser; + +use crate::{cli::ClientCli, client}; + +use super::{serve, HostCli, PackageArgs}; + +#[derive(Parser, Clone, Debug)] +/// Builds and runs the package locally +pub struct Run { + #[command(flatten)] + pub package: PackageArgs, + #[command(flatten)] + pub host: HostCli, + #[command(flatten)] + pub run: ClientCli, +} + +pub fn handle( + rt: &tokio::runtime::Runtime, + args: &Run, + assets: AssetCache, + release_build: bool, +) -> anyhow::Result<()> { + let server_handle = rt.block_on(serve::handle_inner( + &args.package, + &args.host, + assets.clone(), + release_build, + ))?; + + let package_path = args.package.package_path()?; + client::run( + rt, + assets, + server_handle.resolve_as_localhost(), + &args.run, + package_path.fs_path, + ) +} diff --git a/app/src/cli/server.rs b/app/src/cli/package/serve.rs similarity index 79% rename from app/src/cli/server.rs rename to app/src/cli/package/serve.rs index 178ac53b8a..60328b7130 100644 --- a/app/src/cli/server.rs +++ b/app/src/cli/package/serve.rs @@ -1,30 +1,50 @@ -use std::path::PathBuf; - use ambient_native_std::asset_cache::AssetCache; use anyhow::Context; +use clap::Parser; use crate::{ server::{self, ServerHandle}, shared::certs::{CERT, CERT_KEY}, }; -use super::{build::BuildDirectories, HostCli}; +use super::{ + build::{self, BuildDirectories}, + HostCli, PackageArgs, +}; + +#[derive(Parser, Clone, Debug)] +/// Builds and runs the package in server-only mode +pub struct Serve { + #[command(flatten)] + pub package: PackageArgs, + + #[command(flatten)] + pub host: HostCli, +} pub async fn handle( + serve: &Serve, + assets: AssetCache, + release_build: bool, +) -> anyhow::Result { + handle_inner(&serve.package, &serve.host, assets, release_build).await +} + +pub async fn handle_inner( + package: &PackageArgs, host: &HostCli, - view_asset_path: Option, - directories: BuildDirectories, - assets: &AssetCache, + assets: AssetCache, + release_build: bool, ) -> anyhow::Result { let BuildDirectories { build_root_path, main_package_path, main_package_name: _, - } = directories; + } = build::handle_inner(package, &assets, release_build).await?; let manifest = match main_package_path .push("ambient.toml")? - .download_string(assets) + .download_string(&assets) .await { Ok(toml) => ambient_package::Manifest::parse(&toml)?, @@ -39,11 +59,10 @@ pub async fn handle( .unwrap_or(std::env::current_dir()?); let server_handle = server::start( - assets.clone(), + assets, host, build_root_path, main_package_path, - view_asset_path, working_directory, manifest, crypto, diff --git a/app/src/client/mod.rs b/app/src/client/mod.rs index 19ad0b4ef1..688a3cbcc1 100644 --- a/app/src/client/mod.rs +++ b/app/src/client/mod.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, path::PathBuf, sync::Arc, time::Duration}; use ambient_app::{fps_stats, window_title, AppBuilder}; -use ambient_audio::AudioMixer; +use ambient_audio::{AudioMixer, AudioStream}; use ambient_cameras::UICamera; use ambient_client_shared::game_view::GameView; use ambient_core::{ @@ -28,7 +28,7 @@ use ambient_ui_native::{Dock, WindowSized}; use glam::uvec2; use crate::{ - cli::{GoldenImageCommand, RunCli}, + cli::{ClientCli, GoldenImageCommand}, shared::{self, certs::CERT}, }; @@ -39,13 +39,24 @@ pub fn run( rt: &tokio::runtime::Runtime, assets: AssetCache, server_addr: ResolvedAddr, - run: &RunCli, + args: &ClientCli, golden_image_output_dir: Option, - mixer: Option, -) -> ExitStatus { +) -> anyhow::Result<()> { + let audio_stream = if !args.mute_audio { + match AudioStream::new() { + Ok(v) => Some(v), + Err(err) => { + log::error!("Failed to initialize audio stream: {err}"); + None + } + } + } else { + None + }; + let mixer = audio_stream.as_ref().map(|v| v.mixer().clone()); let settings = SettingsKey.get(&assets); - let user_id = match run.user_id.clone().or(settings.general.user_id) { + let user_id = match args.user_id.clone().or(settings.general.user_id) { Some(user_id) => user_id, None => { let user_id = ambient_client_shared::util::random_username(); @@ -57,15 +68,15 @@ pub fn run( } }; - let headless = if run.headless { + let headless = if args.headless { Some(uvec2(600, 600)) } else { None }; - let is_debug = std::env::var("AMBIENT_DEBUGGER").is_ok() || run.debugger; + let is_debug = std::env::var("AMBIENT_DEBUGGER").is_ok() || args.debugger; - let cert = if let Some(ca) = &run.ca { + let cert = if let Some(ca) = &args.ca { match std::fs::read(ca) { Ok(v) => Some(v), Err(err) => { @@ -90,12 +101,12 @@ pub fn run( .headless(headless) .update_title_with_fps_stats(false); - let builder = if let Some((x, y)) = run.window_x.zip(run.window_y) { + let builder = if let Some((x, y)) = args.window_x.zip(args.window_y) { builder.with_window_position_override(glam::ivec2(x, y)) } else { builder }; - let builder = if let Some((w, h)) = run.window_width.zip(run.window_height) { + let builder = if let Some((w, h)) = args.window_width.zip(args.window_height) { builder.with_window_size_override(glam::uvec2(w, h)) } else { builder @@ -109,14 +120,14 @@ pub fn run( let fail_on_version_mismatch = true; #[cfg(not(feature = "production"))] - let fail_on_version_mismatch = !run.dev_allow_version_mismatch; + let fail_on_version_mismatch = !args.dev_allow_version_mismatch; MainApp { server_addr, user_id, fail_on_version_mismatch, show_debug: is_debug, - golden_image_cmd: run.golden_image, + golden_image_cmd: args.golden_image, golden_image_output_dir, cert, mixer, @@ -124,7 +135,19 @@ pub fn run( .el() .spawn_interactive(&mut app.world); - app.run_blocking() + let status = app.run_blocking(); + match status { + ExitStatus::SUCCESS => Ok(()), + ExitStatus::FAILURE => { + anyhow::bail!("The Ambient application exited with a failure status code.") + } + other => { + anyhow::bail!( + "The Ambient application exited with an unknown status code: {:?}", + other + ) + } + } } #[element_component] diff --git a/app/src/main.rs b/app/src/main.rs index 4efafb0738..6169661b19 100644 --- a/app/src/main.rs +++ b/app/src/main.rs @@ -1,9 +1,8 @@ use ambient_native_std::{ asset_cache::{AssetCache, SyncAssetKeyExt}, asset_url::{ContentBaseUrlKey, UsingLocalDebugAssetsKey}, - download_asset::{AssetsCacheOnDisk, ReqwestClientKey}, + download_asset::AssetsCacheOnDisk, }; -use ambient_network::native::client::ResolvedAddr; use ambient_settings::SettingsKey; use clap::Parser; @@ -17,8 +16,7 @@ use anyhow::Context; use cli::{Cli, Commands}; use log::LevelFilter; use serde::Deserialize; -use server::{ServerHandle, QUIC_INTERFACE_PORT}; -use std::path::{Path, PathBuf}; +use std::path::Path; fn main() -> anyhow::Result<()> { let rt = ambient_sys::task::make_native_multithreaded_runtime()?; @@ -62,6 +60,7 @@ fn main() -> anyhow::Result<()> { } // Update some ~~global variables~~ asset keys with package-path derived state + let use_release_build = cli.use_release_build(); if let Some(package_path) = cli.package().map(|p| p.package_path()).transpose()? { if package_path.is_remote() { // package path is a URL, so let's use it as the content base URL @@ -70,140 +69,42 @@ fn main() -> anyhow::Result<()> { // Store a flag that we are using local debug assets // Used for emitting warnings when local debug assets are sent to remote clients - UsingLocalDebugAssetsKey.insert( - &assets, - !package_path.is_remote() && !cli.use_release_build(), - ); + UsingLocalDebugAssetsKey.insert(&assets, !package_path.is_remote() && !use_release_build); } - let release_build = cli.use_release_build(); match &cli.command { - // commands that immediately exit - Commands::New { package, args } => { - let package_path = package.package_path()?; - cli::new_package::handle(&package_path, args).context("Failed to create package") - } - Commands::Assets { command } => rt.block_on(cli::assets::handle(command, &assets)), - Commands::Build { package } => rt.block_on(async { - cli::build::handle(package, &assets, release_build) + // package commands + Commands::Package { package } => cli::package::handle(package, &rt, assets), + Commands::New(args) => rt + .block_on(cli::package::new::handle(args, &assets)) + .context("Failed to create package"), + Commands::Build(build) => rt.block_on(async { + cli::package::build::handle(build, &assets, use_release_build) .await .map(|_| ()) }), - Commands::Deploy { - package, - extra_packages, - api_server, - token, - force_upload, - ensure_running, - context, - } => rt.block_on(async { - cli::deploy::handle( - package, - extra_packages, - &assets, - token.as_deref(), - api_server, - release_build, - *force_upload, - *ensure_running, - context, + Commands::Deploy(deploy) => rt.block_on(cli::package::deploy::handle( + deploy, + &assets, + use_release_build, + )), + Commands::Serve(serve) => rt.block_on(async { + Ok( + cli::package::serve::handle(serve, assets, use_release_build) + .await? + .join() + .await?, ) - .await }), - Commands::Login => rt.block_on(cli::login::handle(&assets)), - - // client - Commands::Join { run, host } => { - let server_addr = rt.block_on(determine_join_addr(&assets, host.as_ref()))?; - cli::client::handle(run, &rt, assets, server_addr, None) - } + Commands::Run(run) => cli::package::run::handle(&rt, run, assets, use_release_build), - // server - Commands::Serve { package, host } => rt.block_on(async { - let server_handle = run_server(&assets, release_build, package, host, None).await?; - Ok(server_handle.join().await?) - }), - - // client+server - Commands::Run { package, host, run } => { - run_client_and_server(&rt, assets, release_build, package, host, run, None) - } - Commands::View { - package, - host, - run, - asset_path, - } => { - let path = Some(asset_path.clone()); - run_client_and_server(&rt, assets, release_build, package, host, run, path) - } - } -} - -async fn determine_join_addr( - assets: &AssetCache, - host: Option<&String>, -) -> anyhow::Result { - match host.cloned() { - Some(mut host) => { - if host.starts_with("http://") || host.starts_with("https://") { - tracing::info!("NOTE: Joining server by http url is still experimental and can be removed without warning."); - - let reqwest = &ReqwestClientKey.get(assets); - host = reqwest.get(host).send().await?.text().await?; - - if host.is_empty() { - anyhow::bail!("Failed to resolve host"); - } - } - if !host.contains(':') { - host = format!("{host}:{QUIC_INTERFACE_PORT}"); - } - ResolvedAddr::lookup_host(&host).await - } - None => Ok(ResolvedAddr::localhost_with_port(QUIC_INTERFACE_PORT)), + // non-package commands + Commands::Assets { assets: command } => rt.block_on(cli::assets::handle(command, &assets)), + Commands::Login => rt.block_on(cli::login::handle(&assets)), + Commands::Join(join) => cli::join::handle(join, &rt, assets), } } -async fn run_server( - assets: &AssetCache, - release_build: bool, - package: &cli::PackageCli, - host: &cli::HostCli, - view_asset_path: Option, -) -> anyhow::Result { - let dirs = cli::build::handle(package, assets, release_build).await?; - cli::server::handle(host, view_asset_path, dirs, assets).await -} - -fn run_client_and_server( - rt: &tokio::runtime::Runtime, - assets: AssetCache, - release_build: bool, - package: &cli::PackageCli, - host: &cli::HostCli, - run: &cli::RunCli, - view_asset_path: Option, -) -> anyhow::Result<()> { - let server_handle = rt.block_on(run_server( - &assets, - release_build, - package, - host, - view_asset_path, - ))?; - - let package_path = package.package_path()?; - cli::client::handle( - run, - rt, - assets, - server_handle.resolve_as_localhost(), - package_path.fs_path, - ) -} - #[derive(Deserialize)] struct LaunchJson { args: Vec, diff --git a/app/src/server/mod.rs b/app/src/server/mod.rs index 4b8a82c6cd..f1f52e093f 100644 --- a/app/src/server/mod.rs +++ b/app/src/server/mod.rs @@ -14,7 +14,7 @@ use ambient_ecs::{ }; use ambient_native_std::{ ambient_version, - asset_cache::{AssetCache, AsyncAssetKeyExt, SyncAssetKeyExt}, + asset_cache::{AssetCache, SyncAssetKeyExt}, asset_url::{AbsAssetUrl, ContentBaseUrlKey, ServerBaseUrlKey}, cb, }; @@ -26,7 +26,6 @@ use ambient_network::{ }, server::{ForkingEvent, ProxySettings, SharedServerState, ShutdownEvent}, }; -use ambient_prefab::PrefabFromUrl; use ambient_sys::task::RuntimeHandle; use anyhow::Context; use axum::{ @@ -39,7 +38,7 @@ use axum::{ use parking_lot::Mutex; use tower_http::{cors::CorsLayer, services::ServeDir}; -use crate::{cli::HostCli, shared}; +use crate::{cli::package::HostCli, shared}; pub mod wasm; @@ -63,7 +62,6 @@ pub async fn start( host_cli: &HostCli, build_root_path: AbsAssetUrl, main_package_path: AbsAssetUrl, - view_asset_path: Option, working_directory: PathBuf, manifest: ambient_package::Manifest, crypto: Crypto, @@ -78,7 +76,11 @@ pub async fn start( .unwrap_or("http://proxy.ambient.run/proxy".to_string()), build_path: build_root_path.clone(), pre_cache_assets: host_cli.proxy_pre_cache_assets, - primary_package_id: manifest.package.id.to_string(), + primary_package_id: manifest + .package + .id + .expect("no package ID in manifest for primary package") + .to_string(), }); let server = if let Some(port) = quic_interface_port { @@ -195,16 +197,6 @@ pub async fn start( .await .unwrap(); - if let Some(asset_path) = view_asset_path { - let asset_path = main_package_path - .push(asset_path.to_string_lossy()) - .expect("FIXME") - .push("prefabs/main.json") - .expect("pushing 'prefabs/main.json' shouldn't fail"); - log::info!("Spawning asset from {:?}", asset_path); - let obj = PrefabFromUrl(asset_path.into()).get(&assets).await.unwrap(); - obj.spawn_into_world(&mut server_world, None); - } log::info!("Starting server"); server .run( diff --git a/campfire/src/package.rs b/campfire/src/package.rs index 2de471ca25..5e9a6010be 100644 --- a/campfire/src/package.rs +++ b/campfire/src/package.rs @@ -30,6 +30,8 @@ pub enum Package { #[arg(long)] include_examples: bool, }, + /// Regenerate IDs for all packages + RegenerateIds, } #[derive(Parser, Clone)] @@ -66,6 +68,7 @@ pub fn main(args: &Package) -> anyhow::Result<()> { token, include_examples, } => deploy_all(token, *include_examples), + Package::RegenerateIds => regenerate_ids(), } } @@ -214,6 +217,26 @@ pub fn get_all_packages( } } } + + { + let core_path = package_path.join("core"); + if core_path.is_dir() { + if core_path.join("ambient.toml").is_file() { + package_paths.push(core_path); + } else { + for core_package in all_directories_in(&core_path)? { + package_paths.push(core_package.path()); + } + } + } + } + + { + let schema_path = package_path.join("schema"); + if schema_path.is_dir() { + package_paths.push(schema_path); + } + } } } if include_examples { @@ -257,3 +280,12 @@ fn get_all_examples(include_testcases: bool) -> anyhow::Result> { Ok(examples) } + +fn regenerate_ids() -> anyhow::Result<()> { + for path in get_all_packages(true, true, true)? { + println!("Regenerating ID for {path:?}"); + run_ambient(&["package", "regenerate-id", &path.to_string_lossy()], true)?; + } + + Ok(()) +} diff --git a/crates/build/src/lib.rs b/crates/build/src/lib.rs index 54c23feb90..b4ee300c06 100644 --- a/crates/build/src/lib.rs +++ b/crates/build/src/lib.rs @@ -164,11 +164,15 @@ pub async fn build_package( .zip(last_modified_time) .is_some_and(|(build, modified)| modified < build); + let package_id = manifest + .package + .id + .as_ref() + .map(|s| s.as_str()) + .unwrap_or("missing ID"); + if last_build_settings.as_ref() == Some(settings) && last_modified_before_build { - tracing::info!( - "Skipping unmodified package \"{package_name}\" ({})", - manifest.package.id - ); + tracing::info!("Skipping unmodified package \"{package_name}\" ({package_id})"); return Ok(BuildResult { build_path, package_name: package_name.clone(), @@ -176,10 +180,7 @@ pub async fn build_package( }); } - tracing::info!( - "Building package \"{package_name}\" ({})", - manifest.package.id - ); + tracing::info!("Building package \"{package_name}\" ({package_id})"); let assets_path = package_path.join("assets"); tokio::fs::create_dir_all(&build_path) diff --git a/crates/deploy/src/lib.rs b/crates/deploy/src/lib.rs index 51ca535df6..2dd825097f 100644 --- a/crates/deploy/src/lib.rs +++ b/crates/deploy/src/lib.rs @@ -11,6 +11,7 @@ use std::{ use ambient_native_std::RUNTIME_USER_AGENT; use ambient_package::Manifest; +use anyhow::Context; use md5::Digest; use tokio_stream::StreamExt; use tonic::{ @@ -36,20 +37,24 @@ const REQUIRED_FILES: [&str; 2] = ["ambient.toml", "metadata.toml"]; pub async fn deploy( api_server: &str, auth_token: &str, - path: impl AsRef, - package_root: impl AsRef, + path: &Path, + package_root: &Path, force_upload: bool, ) -> anyhow::Result<(String, Manifest)> { - let manifest = - Manifest::parse(&tokio::fs::read_to_string(path.as_ref().join("ambient.toml")).await?)?; - - let package_id = manifest.package.id.to_string(); + let manifest = Manifest::parse(&tokio::fs::read_to_string(path.join("ambient.toml")).await?)?; + + let package_id = manifest + .package + .id + .as_ref() + .with_context(|| format!("The package at {path:?} does not have a valid ID"))? + .to_string(); log::info!( "Deploying package \"{}\" ({})", manifest.package.name, package_id ); - let base_path = path.as_ref().to_owned(); + let base_path = path.to_owned(); for (dependency_id, dependency) in &manifest.dependencies { if !dependency.has_remote_dependency() { diff --git a/guest/rust/Cargo.lock b/guest/rust/Cargo.lock index a4e92f6f96..1b4151e8f9 100644 --- a/guest/rust/Cargo.lock +++ b/guest/rust/Cargo.lock @@ -553,6 +553,7 @@ dependencies = [ "ambient_shared_types", "chrono", "convert_case", + "data-encoding", "indexmap 2.0.0", "once_cell", "proc-macro2", @@ -560,6 +561,7 @@ dependencies = [ "rand 0.8.5", "semver", "serde", + "sha2", "syn 1.0.109", "thiserror", "toml 0.7.8", @@ -779,6 +781,15 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bumpalo" version = "3.13.0" @@ -903,6 +914,15 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +[[package]] +name = "cpufeatures" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.3.2" @@ -961,6 +981,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "data-encoding" version = "2.4.0" @@ -1001,6 +1031,16 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "dyn-clonable" version = "0.9.0" @@ -1189,6 +1229,16 @@ dependencies = [ "slab", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.1.16" @@ -2281,6 +2331,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha2" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -2688,6 +2749,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "ulid" version = "1.1.0" diff --git a/guest/rust/examples/assets/basic_model/ambient.toml b/guest/rust/examples/assets/basic_model/ambient.toml index b5408f97ce..bfd46ea1e1 100644 --- a/guest/rust/examples/assets/basic_model/ambient.toml +++ b/guest/rust/examples/assets/basic_model/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_basic_model" +id = "x2zcchov26324tx3av4jvrl5xxealush" name = "Model loading" description = "Load and render a glb model." version = "0.0.1" diff --git a/guest/rust/examples/assets/generate_pipeline/ambient.toml b/guest/rust/examples/assets/generate_pipeline/ambient.toml index d641b1df13..3490706c7c 100644 --- a/guest/rust/examples/assets/generate_pipeline/ambient.toml +++ b/guest/rust/examples/assets/generate_pipeline/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_generate_pipeline" +id = "sssnr4szjawggp2g6drtbubls74c5gwj" name = "Generating pipeline toml" description = "Use code to generate an asset pipeline.toml file" version = "0.0.1" diff --git a/guest/rust/examples/assets/material_overriding/ambient.toml b/guest/rust/examples/assets/material_overriding/ambient.toml index 8a87ef4363..0e2ebae0dc 100644 --- a/guest/rust/examples/assets/material_overriding/ambient.toml +++ b/guest/rust/examples/assets/material_overriding/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_material_overriding" +id = "ib2djsnjew5tb2k5igq6le7rzjdwlvhq" name = "Material overriding" description = "This shows how to combine a model with textures." version = "0.0.1" diff --git a/guest/rust/examples/assets/material_overriding/assets/pipeline.toml b/guest/rust/examples/assets/material_overriding/assets/pipeline.toml index 3764d142dc..12ac9945e0 100644 --- a/guest/rust/examples/assets/material_overriding/assets/pipeline.toml +++ b/guest/rust/examples/assets/material_overriding/assets/pipeline.toml @@ -1,7 +1,7 @@ [[pipelines]] type = "Models" sources = ["*.glb"] -prefab_components = "{ \"ambient_example_material_overriding::is_the_best\": false }" +prefab_components = "{ \"ib2djsnjew5tb2k5igq6le7rzjdwlvhq::is_the_best\": false }" [[pipelines.material_overrides]] diff --git a/guest/rust/examples/assets/unity/ambient.toml b/guest/rust/examples/assets/unity/ambient.toml index b56420f659..bb7c589728 100644 --- a/guest/rust/examples/assets/unity/ambient.toml +++ b/guest/rust/examples/assets/unity/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_unity" +id = "tt7dtctg4qbptrbe6uahkx2lyuudy2gb" name = "Unity" description = "Load and spawn a Unity prefab" version = "0.0.1" diff --git a/guest/rust/examples/basics/input/ambient.toml b/guest/rust/examples/basics/input/ambient.toml index 3edfff1b2d..73b8659d85 100644 --- a/guest/rust/examples/basics/input/ambient.toml +++ b/guest/rust/examples/basics/input/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_input" +id = "d563xtcr72ovuuhfkvsgag6z3wiy5jwr" name = "Input" description = "Read keyboard and mouse inputs from the player." version = "0.0.1" diff --git a/guest/rust/examples/basics/multiplayer/ambient.toml b/guest/rust/examples/basics/multiplayer/ambient.toml index 9d4678eda6..b173e22dd0 100644 --- a/guest/rust/examples/basics/multiplayer/ambient.toml +++ b/guest/rust/examples/basics/multiplayer/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_multiplayer" +id = "lkjek6sipx4m4rkufpxy3lybew2khxxu" name = "Multiplayer" description = "Absolutely minimal multiplayer example." version = "0.0.1" diff --git a/guest/rust/examples/basics/primitives/ambient.toml b/guest/rust/examples/basics/primitives/ambient.toml index 1106c2fd94..268dd8589a 100644 --- a/guest/rust/examples/basics/primitives/ambient.toml +++ b/guest/rust/examples/basics/primitives/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_primitives" +id = "ytdci6e6yiglca2d6awwpi2lt5h6sqvg" name = "Primitives" description = "Draw boxes, spheres and other basic shapes." version = "0.0.1" diff --git a/guest/rust/examples/basics/skinmesh/ambient.toml b/guest/rust/examples/basics/skinmesh/ambient.toml index d8751bf011..19d5d80573 100644 --- a/guest/rust/examples/basics/skinmesh/ambient.toml +++ b/guest/rust/examples/basics/skinmesh/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_skinmesh" +id = "znidkp3d3rqx7ir7bvs2ahx4sfrr2n7n" name = "Skinmesh" description = "Render a character model, with animations." version = "0.0.1" diff --git a/guest/rust/examples/controllers/first_person_camera/ambient.toml b/guest/rust/examples/controllers/first_person_camera/ambient.toml index 5a10da4480..50a5c7178d 100644 --- a/guest/rust/examples/controllers/first_person_camera/ambient.toml +++ b/guest/rust/examples/controllers/first_person_camera/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_first_person_camera" +id = "pfzpi7ypoegwizizej5ojfcsncqa4bet" name = "First person camera" description = "A simple FPS camera and input example." version = "0.0.1" diff --git a/guest/rust/examples/controllers/third_person_camera/ambient.toml b/guest/rust/examples/controllers/third_person_camera/ambient.toml index 8dfba4ae65..8b8d06d71b 100644 --- a/guest/rust/examples/controllers/third_person_camera/ambient.toml +++ b/guest/rust/examples/controllers/third_person_camera/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_third_person_camera" +id = "ie4hdvkvui6t36yzniyex2hc5i2bradc" name = "Third person camera" description = "A simple third person camera controller." version = "0.0.1" diff --git a/guest/rust/examples/intermediate/async/ambient.toml b/guest/rust/examples/intermediate/async/ambient.toml index 1af09a3b6e..a7dbe08f0f 100644 --- a/guest/rust/examples/intermediate/async/ambient.toml +++ b/guest/rust/examples/intermediate/async/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_async" +id = "cezekiuth6khuiykw66bmepsggaoztyv" name = "Async" description = "Learn how to use async/await." version = "0.0.1" diff --git a/guest/rust/examples/intermediate/clientside/ambient.toml b/guest/rust/examples/intermediate/clientside/ambient.toml index e80b851730..639305c394 100644 --- a/guest/rust/examples/intermediate/clientside/ambient.toml +++ b/guest/rust/examples/intermediate/clientside/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_clientside" +id = "xz2ip2ptvxprurqwaiv2nncabcrmml2w" name = "Clientside" description = "How to use client side code." version = "0.0.1" diff --git a/guest/rust/examples/intermediate/dependencies/ambient.toml b/guest/rust/examples/intermediate/dependencies/ambient.toml index 38eb2cb2db..bda1e1eee1 100644 --- a/guest/rust/examples/intermediate/dependencies/ambient.toml +++ b/guest/rust/examples/intermediate/dependencies/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_dependencies" +id = "xjoy27d3i4hc4l7fmlm5pacc2cmxlnlw" name = "Dependencies" description = "Break your project up into packages." version = "0.0.1" diff --git a/guest/rust/examples/intermediate/dependencies/deps/assets/ambient.toml b/guest/rust/examples/intermediate/dependencies/deps/assets/ambient.toml index 9252b6251d..84b47b4a38 100644 --- a/guest/rust/examples/intermediate/dependencies/deps/assets/ambient.toml +++ b/guest/rust/examples/intermediate/dependencies/deps/assets/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_deps_assets" +id = "viyiawgsl5lsiul6pup6pyv6bbt6o3vw" name = "Dependencies (Assets)" version = "0.0.1" content = { type = "Asset", models = true } diff --git a/guest/rust/examples/intermediate/dependencies/deps/code/ambient.toml b/guest/rust/examples/intermediate/dependencies/deps/code/ambient.toml index 5f1e835ff0..4e74bec62d 100644 --- a/guest/rust/examples/intermediate/dependencies/deps/code/ambient.toml +++ b/guest/rust/examples/intermediate/dependencies/deps/code/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_deps_code" +id = "t33j53muycmj4i66en5lheneowad5hbz" name = "Dependencies (Code)" version = "0.0.1" content = { type = "Asset", code = true } diff --git a/guest/rust/examples/intermediate/messaging/ambient.toml b/guest/rust/examples/intermediate/messaging/ambient.toml index 4e5c490c6c..5ad4aeb38a 100644 --- a/guest/rust/examples/intermediate/messaging/ambient.toml +++ b/guest/rust/examples/intermediate/messaging/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_messaging" +id = "of4w7yibjeuokeyypqxmtgqklc6vthln" name = "Messaging" description = "Send and receive data across network and across packages." version = "0.0.1" diff --git a/guest/rust/examples/intermediate/screen_ray/ambient.toml b/guest/rust/examples/intermediate/screen_ray/ambient.toml index 8a6ad904c2..0635b77b9e 100644 --- a/guest/rust/examples/intermediate/screen_ray/ambient.toml +++ b/guest/rust/examples/intermediate/screen_ray/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_screen_ray" +id = "jkr622pbesmaaco76bjc6ll6v4t4lajh" name = "Screen Ray" description = "Intersect a ray from the screen with the world." version = "0.0.1" diff --git a/guest/rust/examples/physics/basics/ambient.toml b/guest/rust/examples/physics/basics/ambient.toml index f3d0d9d274..41ad7fb154 100644 --- a/guest/rust/examples/physics/basics/ambient.toml +++ b/guest/rust/examples/physics/basics/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_physics" +id = "jm77qrzni2f4gied5fy54bia2lqmhebn" name = "Physics" description = "Make things collide and interact in a physically realistic way." version = "0.0.1" diff --git a/guest/rust/examples/physics/visualize_colliders/ambient.toml b/guest/rust/examples/physics/visualize_colliders/ambient.toml index 44678ba437..c1a94c954d 100644 --- a/guest/rust/examples/physics/visualize_colliders/ambient.toml +++ b/guest/rust/examples/physics/visualize_colliders/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "g11no9dcflmdb2qi7m2x7qimdzvv7bhe" +id = "s37z23uqis7ts6ya7v2f66ni23m3upt7" name = "visualize_colliders" version = "0.0.1" content = { type = "Playable" } diff --git a/guest/rust/examples/rendering/decals/ambient.toml b/guest/rust/examples/rendering/decals/ambient.toml index 4faad35ec8..5667c9c07d 100644 --- a/guest/rust/examples/rendering/decals/ambient.toml +++ b/guest/rust/examples/rendering/decals/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_decals" +id = "nd2mwrslb3iyo2bw4jmwcbkuo4mtuyfr" name = "Decals" description = "Render 'stickers' onto any surface." version = "0.0.1" diff --git a/guest/rust/examples/rendering/fog/ambient.toml b/guest/rust/examples/rendering/fog/ambient.toml index c6e8e3f1c7..22143f74f4 100644 --- a/guest/rust/examples/rendering/fog/ambient.toml +++ b/guest/rust/examples/rendering/fog/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_fog" +id = "cfi3occcjea6qqnvaktvsgumnwduqq55" name = "Fog" description = "Create a mystical ambience for your game with fog." version = "0.0.1" diff --git a/guest/rust/examples/rendering/image/ambient.toml b/guest/rust/examples/rendering/image/ambient.toml index d25584d7aa..eb75101026 100644 --- a/guest/rust/examples/rendering/image/ambient.toml +++ b/guest/rust/examples/rendering/image/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_image_quad" +id = "nc2wi4w5w276k4duik4f36ltvec2nv4z" name = "Image" description = "Render 2d images as planes in 3d." version = "0.0.1" diff --git a/guest/rust/examples/rendering/instancing/ambient.toml b/guest/rust/examples/rendering/instancing/ambient.toml index 59c0866a55..c1d26c957e 100644 --- a/guest/rust/examples/rendering/instancing/ambient.toml +++ b/guest/rust/examples/rendering/instancing/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_instancing" +id = "vacm77n5q7uil3giqf6wasadjq32mqr3" name = "Instancing" description = "Render lots of objects with a single draw call." version = "0.0.1" diff --git a/guest/rust/examples/rendering/line/ambient.toml b/guest/rust/examples/rendering/line/ambient.toml index e348b2d9e6..c5e979561c 100644 --- a/guest/rust/examples/rendering/line/ambient.toml +++ b/guest/rust/examples/rendering/line/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_line" +id = "pdvnxkqc5xuwanvxe2yxasswtk23pqij" name = "Line" description = "Draw a line in 3d space." version = "0.0.1" diff --git a/guest/rust/examples/rendering/procedural_generation/ambient.toml b/guest/rust/examples/rendering/procedural_generation/ambient.toml index 19ede84d5c..f17903fc32 100644 --- a/guest/rust/examples/rendering/procedural_generation/ambient.toml +++ b/guest/rust/examples/rendering/procedural_generation/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_procedural_generation" +id = "wke76yvfrkyu25ui5sz3avjivvuypdia" name = "Procedural generation" description = "Generate meshes and textures with code." version = "0.0.1" diff --git a/guest/rust/examples/rendering/raw_text/ambient.toml b/guest/rust/examples/rendering/raw_text/ambient.toml index 7b72ec134d..ac12afc4a5 100644 --- a/guest/rust/examples/rendering/raw_text/ambient.toml +++ b/guest/rust/examples/rendering/raw_text/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_raw_text" +id = "xq7xenkzhaefhpt2wp7wrcsrwvxziyjm" name = "Raw Text" description = "Draw 2d text in 3d." version = "0.0.1" diff --git a/guest/rust/examples/rendering/samplers/ambient.toml b/guest/rust/examples/rendering/samplers/ambient.toml index f2062e3861..fba6ead468 100644 --- a/guest/rust/examples/rendering/samplers/ambient.toml +++ b/guest/rust/examples/rendering/samplers/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_samplers" +id = "vynje2qmxhzilneirqbzuhgxkq4nvjto" name = "samplers" description = "How to work with samplers." version = "0.0.1" diff --git a/guest/rust/examples/rendering/sun/ambient.toml b/guest/rust/examples/rendering/sun/ambient.toml index ebb9641cd5..4aa956b370 100644 --- a/guest/rust/examples/rendering/sun/ambient.toml +++ b/guest/rust/examples/rendering/sun/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_sun" +id = "solyomvjgvfpd7x2k6a6xiajzynxfmex" name = "Sun" description = "Create a sun light." version = "0.0.1" diff --git a/guest/rust/examples/rendering/transparency/ambient.toml b/guest/rust/examples/rendering/transparency/ambient.toml index 5d26b56f2f..895f01c37c 100644 --- a/guest/rust/examples/rendering/transparency/ambient.toml +++ b/guest/rust/examples/rendering/transparency/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_transparency" +id = "devasx4mng2jjjaw65mmicqc45rngafa" name = "Transparency" description = "Draw translucent objects." version = "0.0.1" diff --git a/guest/rust/examples/ui/audio_ctrl/ambient.toml b/guest/rust/examples/ui/audio_ctrl/ambient.toml index f4aaf4af0a..2f3516016a 100644 --- a/guest/rust/examples/ui/audio_ctrl/ambient.toml +++ b/guest/rust/examples/ui/audio_ctrl/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_audio_ctrl" +id = "jmqsaivuk3nzk3inbdfj5mx4kqjmofdv" name = "Audio control" description = "Test out volume and panning." version = "0.0.1" diff --git a/guest/rust/examples/ui/auto_editor/ambient.toml b/guest/rust/examples/ui/auto_editor/ambient.toml index 2e9101bab3..0e3eb65e03 100644 --- a/guest/rust/examples/ui/auto_editor/ambient.toml +++ b/guest/rust/examples/ui/auto_editor/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_auto_editor" +id = "clwaexkinp2lnxm2h6r4gznp6gqfrmne" name = "Auto editor" description = "Automatically create edit UI for any structs, enums etc." version = "0.0.1" diff --git a/guest/rust/examples/ui/button/ambient.toml b/guest/rust/examples/ui/button/ambient.toml index cd634e74a6..c9295f935a 100644 --- a/guest/rust/examples/ui/button/ambient.toml +++ b/guest/rust/examples/ui/button/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_button" +id = "gcmnpmewi3axaamblf5zeldtwk4u2u3m" name = "Button" description = "Well.. it's a button" version = "0.0.1" diff --git a/guest/rust/examples/ui/clock/ambient.toml b/guest/rust/examples/ui/clock/ambient.toml index 9c9f690688..7236c8c24c 100644 --- a/guest/rust/examples/ui/clock/ambient.toml +++ b/guest/rust/examples/ui/clock/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_clock" +id = "fsv4zmeyotsu4lhji4rv6kivla5vmifi" name = "Clock" description = "A slightly more advanced example." version = "0.0.1" diff --git a/guest/rust/examples/ui/counter/ambient.toml b/guest/rust/examples/ui/counter/ambient.toml index c67b22b651..914fb7a5cc 100644 --- a/guest/rust/examples/ui/counter/ambient.toml +++ b/guest/rust/examples/ui/counter/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_counter" +id = "t5rzmpq5h7dwjkxe7zugthxlauvon5mp" name = "Counter" description = "Get started learning state management with Elements." version = "0.0.1" diff --git a/guest/rust/examples/ui/dock_layout/ambient.toml b/guest/rust/examples/ui/dock_layout/ambient.toml index 1272577dc4..6812aed8d0 100644 --- a/guest/rust/examples/ui/dock_layout/ambient.toml +++ b/guest/rust/examples/ui/dock_layout/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_dock_layout" +id = "pdgdtcgm5fxbrhvdcliwz2eogtihrqo3" name = "Dock Layout" description = "Top-down layout." version = "0.0.1" diff --git a/guest/rust/examples/ui/editors/ambient.toml b/guest/rust/examples/ui/editors/ambient.toml index 0c2330f2fc..4db9533fbc 100644 --- a/guest/rust/examples/ui/editors/ambient.toml +++ b/guest/rust/examples/ui/editors/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_editors" +id = "ezucewnosj4da35cbwtopwzrqbaea6jx" name = "Editors" description = "Text editor, number editor, list editor etc. etc." version = "0.0.1" diff --git a/guest/rust/examples/ui/flow_layout/ambient.toml b/guest/rust/examples/ui/flow_layout/ambient.toml index e2e9f9a10a..63e133c4e5 100644 --- a/guest/rust/examples/ui/flow_layout/ambient.toml +++ b/guest/rust/examples/ui/flow_layout/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_flow_layout" +id = "bok7gwabmlyzlwbddf4nfur4jyrz27ji" name = "Flow Layout" description = "Bottom-up layout." version = "0.0.1" diff --git a/guest/rust/examples/ui/image/ambient.toml b/guest/rust/examples/ui/image/ambient.toml index 7d73078a9c..e5406c61ad 100644 --- a/guest/rust/examples/ui/image/ambient.toml +++ b/guest/rust/examples/ui/image/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_image" +id = "t6vnxnggki32io3sobzeawxn5peyw3e3" name = "Image" description = "Using a 2d image in the UI." version = "0.0.1" diff --git a/guest/rust/examples/ui/rect/ambient.toml b/guest/rust/examples/ui/rect/ambient.toml index 441021a611..b40667b44e 100644 --- a/guest/rust/examples/ui/rect/ambient.toml +++ b/guest/rust/examples/ui/rect/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_rect" +id = "n3xokyl3yn4vd3lzfjlvbbtgnnmqlnjo" name = "Rect" description = "A rectangle with border, rounded corners and background image." version = "0.0.1" diff --git a/guest/rust/examples/ui/screens/ambient.toml b/guest/rust/examples/ui/screens/ambient.toml index 0851685432..51c764c4b1 100644 --- a/guest/rust/examples/ui/screens/ambient.toml +++ b/guest/rust/examples/ui/screens/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_screens" +id = "ucrvg2az42ep6ge43ewuz6mqkvmvcxdb" name = "Screens" description = "Or 'pages'. For instance; lobby screen, loading screen etc." version = "0.0.1" diff --git a/guest/rust/examples/ui/scroll/ambient.toml b/guest/rust/examples/ui/scroll/ambient.toml index 1728045de0..ed1bd967e2 100644 --- a/guest/rust/examples/ui/scroll/ambient.toml +++ b/guest/rust/examples/ui/scroll/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_scroll" +id = "u5bpyalmmxsdsnlwfnamh7kvxjfodvh7" name = "Scroll are" description = "Use the mouse wheel to reveal more content." version = "0.0.1" diff --git a/guest/rust/examples/ui/slider/ambient.toml b/guest/rust/examples/ui/slider/ambient.toml index 321c51fef4..2ecea17f73 100644 --- a/guest/rust/examples/ui/slider/ambient.toml +++ b/guest/rust/examples/ui/slider/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_slider" +id = "d4ctdtfmrwpccnqlb5pyu47tdah3rck5" name = "Slider" description = "Different number sliders." version = "0.0.1" diff --git a/guest/rust/examples/ui/text/ambient.toml b/guest/rust/examples/ui/text/ambient.toml index 3430f58d81..84081d7bdf 100644 --- a/guest/rust/examples/ui/text/ambient.toml +++ b/guest/rust/examples/ui/text/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_text" +id = "lxik5hg25fs2gfcsqxj7dytf7dbvnhzx" name = "Text" description = "Different fonts, sizes and colors etc." version = "0.0.1" diff --git a/guest/rust/examples/ui/todo/ambient.toml b/guest/rust/examples/ui/todo/ambient.toml index 6f5f7ff1f9..09413d7a3a 100644 --- a/guest/rust/examples/ui/todo/ambient.toml +++ b/guest/rust/examples/ui/todo/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_todo" +id = "jruv4zn5tfe2s3kpyhhq7z3uezbi27cv" name = "Todo" description = "Classic todo example, but in multiplayer." version = "0.0.1" diff --git a/guest/rust/packages/assets/kenney_digital_audio/ambient.toml b/guest/rust/packages/assets/kenney_digital_audio/ambient.toml index 376dd18ee7..974ebdc400 100644 --- a/guest/rust/packages/assets/kenney_digital_audio/ambient.toml +++ b/guest/rust/packages/assets/kenney_digital_audio/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "kenney_digital_audio" +id = "k7svgbw5j6orlwzj45koeownlodsdbth" name = "Kenney's Digital Audio" authors = ["Kenney"] description = "https://www.kenney.nl/assets/digital-audio for Ambient. (Uploaded by Ambient, not Kenney.)" diff --git a/guest/rust/packages/assets/kenney_impact_sounds/ambient.toml b/guest/rust/packages/assets/kenney_impact_sounds/ambient.toml index 0a7aba7b3b..dfd46be310 100644 --- a/guest/rust/packages/assets/kenney_impact_sounds/ambient.toml +++ b/guest/rust/packages/assets/kenney_impact_sounds/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "kenney_impact_sounds" +id = "e4unr4x2lz2ov7dsd5vnjylbykwixvv2" name = "Kenney's Impact Sounds" authors = ["Kenney"] description = "https://www.kenney.nl/assets/impact-sounds for Ambient. (Uploaded by Ambient, not Kenney.)" diff --git a/guest/rust/packages/assets/kenney_space_kit/ambient.toml b/guest/rust/packages/assets/kenney_space_kit/ambient.toml index 2ae2f14660..bd629cd51c 100644 --- a/guest/rust/packages/assets/kenney_space_kit/ambient.toml +++ b/guest/rust/packages/assets/kenney_space_kit/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "wrzx497nolk2dynyy6cs25v0u25qrpp9" +id = "llhdryqkfsr6gy4f26wbolh4kfwnzn3c" name = "Kenney's Space Kit" authors = ["Kenney"] description = "https://www.kenney.nl/assets/space-kit for Ambient. (Uploaded by Ambient, not Kenney.)" diff --git a/guest/rust/packages/games/afps/ambient.toml b/guest/rust/packages/games/afps/ambient.toml index 88266736a7..9197ca75ca 100644 --- a/guest/rust/packages/games/afps/ambient.toml +++ b/guest/rust/packages/games/afps/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "afps" +id = "qvd3idif3tkax2on2bw6ia3uf6al2tyv" name = "afps" version = "0.0.1" content = { type = "Playable" } diff --git a/guest/rust/packages/games/afps/core/fpsaudio/ambient.toml b/guest/rust/packages/games/afps/core/fpsaudio/ambient.toml index a80d4ad983..f00341cbd6 100644 --- a/guest/rust/packages/games/afps/core/fpsaudio/ambient.toml +++ b/guest/rust/packages/games/afps/core/fpsaudio/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "afps_fpsaudio" +id = "yfyltsyubkah4ricdvo65gomxktb7zf6" name = "AFPS Audio" version = "0.0.1" content = { type = "Asset", audio = true, code = true } diff --git a/guest/rust/packages/games/afps/core/fpsmodel/ambient.toml b/guest/rust/packages/games/afps/core/fpsmodel/ambient.toml index d94917ea48..e586e3fa8a 100644 --- a/guest/rust/packages/games/afps/core/fpsmodel/ambient.toml +++ b/guest/rust/packages/games/afps/core/fpsmodel/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "afps_fpsmodel" +id = "avztzukrpdpswuxb6s3paryhp4wmlckj" name = "AFPS Model" version = "0.0.1" content = { type = "Asset", models = true, code = true } diff --git a/guest/rust/packages/games/afps/core/fpsmovement/ambient.toml b/guest/rust/packages/games/afps/core/fpsmovement/ambient.toml index 329b54437e..a695940040 100644 --- a/guest/rust/packages/games/afps/core/fpsmovement/ambient.toml +++ b/guest/rust/packages/games/afps/core/fpsmovement/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "afps_fpsmovement" +id = "ldju5agsejzafvrl4qz6np6gerpokcah" name = "AFPS Movmement" version = "0.0.1" content = { type = "Asset", code = true } diff --git a/guest/rust/packages/games/afps/core/fpsrule/ambient.toml b/guest/rust/packages/games/afps/core/fpsrule/ambient.toml index e4c184a7ee..ac8e6f3dcd 100644 --- a/guest/rust/packages/games/afps/core/fpsrule/ambient.toml +++ b/guest/rust/packages/games/afps/core/fpsrule/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "afps_fpsrule" +id = "suth5lljxzfjixfyxyw3ggvrtyrqa3mf" name = "AFPS Rule" version = "0.0.1" content = { type = "Asset", code = true } diff --git a/guest/rust/packages/games/afps/core/fpsui/ambient.toml b/guest/rust/packages/games/afps/core/fpsui/ambient.toml index 1f0c49a332..1efcc8c9f7 100644 --- a/guest/rust/packages/games/afps/core/fpsui/ambient.toml +++ b/guest/rust/packages/games/afps/core/fpsui/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "afps_fpsui" +id = "d5t7njlgmc3wohivbeuag5ouetzontrm" name = "AFPS UI" version = "0.0.1" content = { type = "Asset", textures = true, code = true } diff --git a/guest/rust/packages/games/afps/mods/scene/ambient.toml b/guest/rust/packages/games/afps/mods/scene/ambient.toml index 9119339b67..8cb5746421 100644 --- a/guest/rust/packages/games/afps/mods/scene/ambient.toml +++ b/guest/rust/packages/games/afps/mods/scene/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "afps_scene" +id = "z6o5phfdxatg7vwc6haah6gxni3vf3y2" name = "AFPS Scene" version = "0.0.1" content = { type = "Asset", models = true, code = true } diff --git a/guest/rust/packages/games/afps/mods/spraypaint/ambient.toml b/guest/rust/packages/games/afps/mods/spraypaint/ambient.toml index a56115e133..3ec1b1013a 100644 --- a/guest/rust/packages/games/afps/mods/spraypaint/ambient.toml +++ b/guest/rust/packages/games/afps/mods/spraypaint/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "afps_spraypaint" +id = "op2g7jibpmzgvsqh5f2gi3seux6l6o5h" name = "AFPS Spraypaint" version = "0.0.1" content = { type = "Asset", models = true, textures = true, code = true } diff --git a/guest/rust/packages/games/afps/mods/world_latency/ambient.toml b/guest/rust/packages/games/afps/mods/world_latency/ambient.toml index 222211e7d9..24ae9faf4d 100644 --- a/guest/rust/packages/games/afps/mods/world_latency/ambient.toml +++ b/guest/rust/packages/games/afps/mods/world_latency/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "afps_world_latency" +id = "fclqpkeyujrl3jeb6na6qmkl6jsumyoq" name = "AFPS World Latency" description = "World latency is a simple utility that displays the relative latency # of world streamed from the server as seen by all players in the world." version = "0.0.1" diff --git a/guest/rust/packages/games/afps/mods/zombie/ambient.toml b/guest/rust/packages/games/afps/mods/zombie/ambient.toml index 4a8a509c88..87cf1322a4 100644 --- a/guest/rust/packages/games/afps/mods/zombie/ambient.toml +++ b/guest/rust/packages/games/afps/mods/zombie/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "afps_zombie" +id = "du7ethjmsamrvmqoznmoedkxiongpj5g" name = "AFPS Zombie" version = "0.0.1" content = { type = "Asset", models = true, animations = true, code = true } diff --git a/guest/rust/packages/games/afps/schema/ambient.toml b/guest/rust/packages/games/afps/schema/ambient.toml index 5eb9b970cb..87bd33089b 100644 --- a/guest/rust/packages/games/afps/schema/ambient.toml +++ b/guest/rust/packages/games/afps/schema/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "afps_schema" +id = "thx4rfn4t3nbt4lbgub5bs7bejlawjk3" name = "AFPS Schema" version = "0.0.1" content = { type = "Asset", schema = true } diff --git a/guest/rust/packages/games/arkanoid/ambient.toml b/guest/rust/packages/games/arkanoid/ambient.toml index bd1a6b982d..dbff8cd00c 100644 --- a/guest/rust/packages/games/arkanoid/ambient.toml +++ b/guest/rust/packages/games/arkanoid/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_arkanoid" +id = "t6opuz533binrqqjsbgcezprtfa6vpyy" name = "Arkanoid" description = "The classic." version = "0.0.1" diff --git a/guest/rust/packages/games/minigolf/ambient.toml b/guest/rust/packages/games/minigolf/ambient.toml index 9474d9cac5..656af55d1e 100644 --- a/guest/rust/packages/games/minigolf/ambient.toml +++ b/guest/rust/packages/games/minigolf/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_minigolf" +id = "uigiqyr7qugdncpzkyzinvwxh26daahx" name = "Minigolf" description = "Can you hit a hole-in-one?" version = "0.0.1" diff --git a/guest/rust/packages/games/music_sequencer/ambient.toml b/guest/rust/packages/games/music_sequencer/ambient.toml index cda33ab9b3..11132b664c 100644 --- a/guest/rust/packages/games/music_sequencer/ambient.toml +++ b/guest/rust/packages/games/music_sequencer/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_music_sequencer" +id = "ar7fnf3vl72bdb77nvnzbjpvps3lhvas" name = "Music sequencer" description = "Make some sweet beats." version = "0.0.1" diff --git a/guest/rust/packages/games/pong/ambient.toml b/guest/rust/packages/games/pong/ambient.toml index a5d774f394..4fbf5e847f 100644 --- a/guest/rust/packages/games/pong/ambient.toml +++ b/guest/rust/packages/games/pong/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_pong" +id = "h3gv2vnpcajq75woh5nmiemeahfpaku4" name = "Pong" description = "Minimal multiplayer pong." version = "0.0.1" diff --git a/guest/rust/packages/games/tangent/ambient.toml b/guest/rust/packages/games/tangent/ambient.toml index 1bdcfd6d8f..bc0562ae3e 100644 --- a/guest/rust/packages/games/tangent/ambient.toml +++ b/guest/rust/packages/games/tangent/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "tangent" +id = "t5qdqwpkoxtelvafs7qpvzhaoperwfpt" name = "Tangent" version = "0.1.0" content = { type = "Playable" } diff --git a/guest/rust/packages/games/tangent/core/ambient.toml b/guest/rust/packages/games/tangent/core/ambient.toml index 2abd7590c4..5a7e4bfe35 100644 --- a/guest/rust/packages/games/tangent/core/ambient.toml +++ b/guest/rust/packages/games/tangent/core/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "tangent_core" +id = "itzh3wovmdje4ttrmo6wrravaaxp6b52" name = "Tangent Core" version = "0.1.0" content = { type = "Playable" } diff --git a/guest/rust/packages/games/tangent/mods/camera_follow/ambient.toml b/guest/rust/packages/games/tangent/mods/camera_follow/ambient.toml index 0400b526e5..5d67e39c62 100644 --- a/guest/rust/packages/games/tangent/mods/camera_follow/ambient.toml +++ b/guest/rust/packages/games/tangent/mods/camera_follow/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "tangent_camera_follow" +id = "mkd4mhans4bdn3mvmt45vxqbxepdhys3" name = "Tangent Camera: Follow" version = "0.1.0" content = { type = "Mod", for_playables = ["tangent"] } diff --git a/guest/rust/packages/games/tangent/mods/camera_topdown/ambient.toml b/guest/rust/packages/games/tangent/mods/camera_topdown/ambient.toml index 92887371d1..01c1eae880 100644 --- a/guest/rust/packages/games/tangent/mods/camera_topdown/ambient.toml +++ b/guest/rust/packages/games/tangent/mods/camera_topdown/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "tangent_camera_topdown" +id = "h5q5ndu5znuaa3kicfsbrf6zmfd5ygpx" name = "Tangent Camera: Top-down" version = "0.1.0" content = { type = "Mod", for_playables = ["tangent"] } diff --git a/guest/rust/packages/games/tangent/mods/class_assault/ambient.toml b/guest/rust/packages/games/tangent/mods/class_assault/ambient.toml index 7fdf403846..ff00730f8f 100644 --- a/guest/rust/packages/games/tangent/mods/class_assault/ambient.toml +++ b/guest/rust/packages/games/tangent/mods/class_assault/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ob731abrl0d51ihp3zgx1e8qtdiv7f12" +id = "j32xi2gg5rvgob2cu7uirdbtj5ce4jw7" name = "Tangent Class: Assault" version = "0.1.0" content = { type = "Mod", for_playables = ["tangent"] } diff --git a/guest/rust/packages/games/tangent/mods/class_scout/ambient.toml b/guest/rust/packages/games/tangent/mods/class_scout/ambient.toml index 0cd05a33a3..a482b7b25e 100644 --- a/guest/rust/packages/games/tangent/mods/class_scout/ambient.toml +++ b/guest/rust/packages/games/tangent/mods/class_scout/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "haq3c8ra5r7u3mhaynqqdvtcmgb6l54p" +id = "fvn74ns4ozf3gn42vmowphmvmpsfklbi" name = "Tangent Class: Scout" version = "0.1.0" content = { type = "Mod", for_playables = ["tangent"] } diff --git a/guest/rust/packages/games/tangent/mods/class_tank/ambient.toml b/guest/rust/packages/games/tangent/mods/class_tank/ambient.toml index c9434d07b6..8ed8169b0e 100644 --- a/guest/rust/packages/games/tangent/mods/class_tank/ambient.toml +++ b/guest/rust/packages/games/tangent/mods/class_tank/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "o0j4qyxwhcf9vukzslsvhrkj2sv5mf4x" +id = "ys6g5noe72fbhnoj6l3psjq75knd7gko" name = "Tangent Class: Tank" version = "0.1.0" content = { type = "Mod", for_playables = ["tangent"] } diff --git a/guest/rust/packages/games/tangent/mods/gun_laser/ambient.toml b/guest/rust/packages/games/tangent/mods/gun_laser/ambient.toml index 6e67a71920..0819273bf0 100644 --- a/guest/rust/packages/games/tangent/mods/gun_laser/ambient.toml +++ b/guest/rust/packages/games/tangent/mods/gun_laser/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "uojjsmn9xs1pj3xzz16rprjot0kk3p2o" +id = "jyp2hh3fpjfe7kaos36zbdztfypqip3m" name = "Tangent Gun: Laser" version = "0.1.0" content = { type = "Mod", for_playables = ["tangent"] } diff --git a/guest/rust/packages/games/tangent/mods/level_cubicide/ambient.toml b/guest/rust/packages/games/tangent/mods/level_cubicide/ambient.toml index 2dd3388a4b..57fc4c1be7 100644 --- a/guest/rust/packages/games/tangent/mods/level_cubicide/ambient.toml +++ b/guest/rust/packages/games/tangent/mods/level_cubicide/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "tangent_level_cubicide" +id = "gzbamly2shtnz3siisf3mdzglsi67vul" name = "Tangent Level: Cubicide" version = "0.1.0" content = { type = "Mod", for_playables = ["tangent"] } diff --git a/guest/rust/packages/games/tangent/mods/pickup_health/ambient.toml b/guest/rust/packages/games/tangent/mods/pickup_health/ambient.toml index 9542f09038..b0bae393f5 100644 --- a/guest/rust/packages/games/tangent/mods/pickup_health/ambient.toml +++ b/guest/rust/packages/games/tangent/mods/pickup_health/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "tangent_pickup_health" +id = "skpc6fwjkbidr7a6pmx4mab6zl37oiut" name = "Tangent Pickup: Health" version = "0.1.0" content = { type = "Mod", for_playables = ["tangent"] } diff --git a/guest/rust/packages/games/tangent/mods/ui_class_selection/ambient.toml b/guest/rust/packages/games/tangent/mods/ui_class_selection/ambient.toml index f08831e3ea..23182de4cc 100644 --- a/guest/rust/packages/games/tangent/mods/ui_class_selection/ambient.toml +++ b/guest/rust/packages/games/tangent/mods/ui_class_selection/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "tangent_ui_class_selection" +id = "hs7ygpw4pmpsixtcohdcvzxwmrfzubvi" name = "Tangent UI: Class Selection" version = "0.1.0" content = { type = "Mod", for_playables = ["tangent"] } diff --git a/guest/rust/packages/games/tangent/mods/ui_holohud/ambient.toml b/guest/rust/packages/games/tangent/mods/ui_holohud/ambient.toml index 7efd0a842b..0d4d3e214f 100644 --- a/guest/rust/packages/games/tangent/mods/ui_holohud/ambient.toml +++ b/guest/rust/packages/games/tangent/mods/ui_holohud/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "tangent_ui_holohud" +id = "xadcwjtmzuagnoydry5h4psaph3hccbw" name = "Tangent HUD: Hologram" version = "0.1.0" content = { type = "Mod", for_playables = ["tangent"] } diff --git a/guest/rust/packages/games/tangent/schema/ambient.toml b/guest/rust/packages/games/tangent/schema/ambient.toml index 6f259f202a..ccb3b6d793 100644 --- a/guest/rust/packages/games/tangent/schema/ambient.toml +++ b/guest/rust/packages/games/tangent/schema/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "tangent_schema" +id = "mwrcsok65na7owrbdococ5sthr3ccskc" name = "Tangent Schema" version = "0.1.0" content = { type = "Asset", schema = true } diff --git a/guest/rust/packages/games/tictactoe/ambient.toml b/guest/rust/packages/games/tictactoe/ambient.toml index 4388c8e199..52b7bcc5f9 100644 --- a/guest/rust/packages/games/tictactoe/ambient.toml +++ b/guest/rust/packages/games/tictactoe/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_example_tictactoe" +id = "thr5tsq3g3vvf7ilap2jfu6bpoyas53s" name = "Tic Tac Toe" description = "Aka five-in-a-row." version = "0.0.1" diff --git a/guest/rust/packages/schemas/editor/ambient.toml b/guest/rust/packages/schemas/editor/ambient.toml index 3bb56589e0..6968cf8946 100644 --- a/guest/rust/packages/schemas/editor/ambient.toml +++ b/guest/rust/packages/schemas/editor/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "editor_schema" +id = "n7xfnlfzdmnvj7bqasfdhqftbtdi27ah" name = "Editor Schema" version = "0.0.1" description = "Schema for the editor." diff --git a/guest/rust/packages/schemas/game_object/ambient.toml b/guest/rust/packages/schemas/game_object/ambient.toml index d9bc995a86..1a59884261 100644 --- a/guest/rust/packages/schemas/game_object/ambient.toml +++ b/guest/rust/packages/schemas/game_object/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "hw3bncgdihgy31w9nkv7ctshsbbyrtgm" +id = "hvxms7i2px7krvkm23sxfjxsjqlcmtb5" name = "Game Object" description = "Schema for game objects" version = "0.0.1" diff --git a/guest/rust/packages/schemas/unit/ambient.toml b/guest/rust/packages/schemas/unit/ambient.toml index 3caa84a1a7..4707a7a672 100644 --- a/guest/rust/packages/schemas/unit/ambient.toml +++ b/guest/rust/packages/schemas/unit/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "unit" +id = "afl5yv5ya35vbuaj3aido22cwjzat25z" name = "Unit" description = "Schema for units in games" version = "0.0.1" diff --git a/guest/rust/packages/std/base_assets/ambient.toml b/guest/rust/packages/std/base_assets/ambient.toml index 7c97ab3f4a..516414bffb 100644 --- a/guest/rust/packages/std/base_assets/ambient.toml +++ b/guest/rust/packages/std/base_assets/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "base_assets" +id = "n7a4j7htvenss35tsnfvegbhxuwij5il" name = "base_assets" version = "0.0.1" content = { type = "Asset", models = true } diff --git a/guest/rust/packages/std/character_animation/ambient.toml b/guest/rust/packages/std/character_animation/ambient.toml index 79f7988643..0501f2692a 100644 --- a/guest/rust/packages/std/character_animation/ambient.toml +++ b/guest/rust/packages/std/character_animation/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "character_animation" +id = "d3y3wbexrclipsykysumem3fthkudwx2" name = "Character animation" version = "0.0.1" content = { type = "Asset", animations = true, code = true } diff --git a/guest/rust/packages/std/character_movement/ambient.toml b/guest/rust/packages/std/character_movement/ambient.toml index 3b564f2ef8..1330144a20 100644 --- a/guest/rust/packages/std/character_movement/ambient.toml +++ b/guest/rust/packages/std/character_movement/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "character_movement" +id = "lktsfudbjw2qikhyumt573ozxhadkiwm" name = "character_movement" version = "0.0.1" content = { type = "Asset", code = true } diff --git a/guest/rust/packages/std/explosion/ambient.toml b/guest/rust/packages/std/explosion/ambient.toml index d777d5cd03..612d6cefe0 100644 --- a/guest/rust/packages/std/explosion/ambient.toml +++ b/guest/rust/packages/std/explosion/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "xm4ev8iuaca28ijjt3p55e305mixopfw" +id = "cneomdouziieskjvs3szwmigzotofjzs" name = "Explosion" version = "0.0.1" content = { type = "Asset", code = true } diff --git a/guest/rust/packages/std/fps_controller/ambient.toml b/guest/rust/packages/std/fps_controller/ambient.toml index 2ecf39cd2d..4903a7058a 100644 --- a/guest/rust/packages/std/fps_controller/ambient.toml +++ b/guest/rust/packages/std/fps_controller/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "fps_controller" +id = "vuph6dqdj6li4apmcgomn3faudcbfz56" name = "fps_controller" version = "0.0.1" content = { type = "Asset", code = true } diff --git a/guest/rust/packages/std/hide_cursor/ambient.toml b/guest/rust/packages/std/hide_cursor/ambient.toml index 86c19fb059..a5dc6641fc 100644 --- a/guest/rust/packages/std/hide_cursor/ambient.toml +++ b/guest/rust/packages/std/hide_cursor/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "hide_cursor" +id = "xar372tfo2oswb4pkvx7h7o3rxi6tap6" name = "hide_cursor" version = "0.0.1" content = { type = "Asset", code = true } diff --git a/guest/rust/packages/std/nameplates/ambient.toml b/guest/rust/packages/std/nameplates/ambient.toml index 0c441e9857..f14ba6d918 100644 --- a/guest/rust/packages/std/nameplates/ambient.toml +++ b/guest/rust/packages/std/nameplates/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "hzjutdjnny0qt96y0dwb7rng89vf2dl5" +id = "per6j2iqhj3jz4da3fqr75jcj2kqjooo" name = "Nameplates" version = "0.0.1" content = { type = "Asset", code = true } diff --git a/guest/rust/packages/std/orbit_camera/ambient.toml b/guest/rust/packages/std/orbit_camera/ambient.toml index d9585181a7..4b0680a79f 100644 --- a/guest/rust/packages/std/orbit_camera/ambient.toml +++ b/guest/rust/packages/std/orbit_camera/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "orbit_camera" +id = "tijz7x6fimbgu24sbbtp4nllhfxbgblp" name = "Orbit Camera" description = "Implements a clientside-only orbit camera." version = "0.0.1" diff --git a/guest/rust/packages/tools/console/ambient.toml b/guest/rust/packages/tools/console/ambient.toml index 58a60f8236..56f0de9ef9 100644 --- a/guest/rust/packages/tools/console/ambient.toml +++ b/guest/rust/packages/tools/console/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "console" +id = "wqkvthxjifxdwgi4hc4efmtjct6tljbw" name = "Console" version = "0.0.1" content = { type = "Tool" } diff --git a/guest/rust/packages/tools/editor/ambient.toml b/guest/rust/packages/tools/editor/ambient.toml index 1ea7c3c7e5..be682045f0 100644 --- a/guest/rust/packages/tools/editor/ambient.toml +++ b/guest/rust/packages/tools/editor/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "editor" +id = "xr6whcy65gn3vlzrp2ssyn7udcbxb6mu" name = "Editor" version = "0.0.1" content = { type = "Tool" } diff --git a/guest/rust/packages/tools/package_manager/ambient.toml b/guest/rust/packages/tools/package_manager/ambient.toml index 3529f46d10..79040cf51f 100644 --- a/guest/rust/packages/tools/package_manager/ambient.toml +++ b/guest/rust/packages/tools/package_manager/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "package_manager" +id = "hr4pxz7kfhzgimicoyh65ydel3aehuhk" name = "Package Manager" version = "0.0.1" content = { type = "Tool" } diff --git a/guest/rust/packages/tools/package_manager/src/server/package_manager.rs b/guest/rust/packages/tools/package_manager/src/server/package_manager.rs index 34a71ac44e..a21ed0d04d 100644 --- a/guest/rust/packages/tools/package_manager/src/server/package_manager.rs +++ b/guest/rust/packages/tools/package_manager/src/server/package_manager.rs @@ -89,14 +89,16 @@ async fn process_request() -> anyhow::Result { } } - packages_json.push(serde_json::to_string(&PackageJson { - url, - name: manifest.package.name, - id: manifest.package.id.to_string(), - version: manifest.package.version.to_string(), - authors: manifest.package.authors, - description: manifest.package.description, - })?); + if let Some(id) = manifest.package.id { + packages_json.push(serde_json::to_string(&PackageJson { + url, + name: manifest.package.name, + id: id.to_string(), + version: manifest.package.version.to_string(), + authors: manifest.package.authors, + description: manifest.package.description, + })?); + } } Ok(PackageRemoteResponse { diff --git a/guest/rust/testcases/588-prefab-despawn-panic/ambient.toml b/guest/rust/testcases/588-prefab-despawn-panic/ambient.toml index 137d27ce34..fa99697e74 100644 --- a/guest/rust/testcases/588-prefab-despawn-panic/ambient.toml +++ b/guest/rust/testcases/588-prefab-despawn-panic/ambient.toml @@ -1,5 +1,5 @@ [package] -id = "ambient_testcase_i588" +id = "zzcyk2wlcelbpd25bzsjffzdpjmjsnkl" name = "Test Case 588" version = "0.0.1" description = "Reproduces https://github.com/AmbientRun/Ambient/issues/588" diff --git a/schema/ambient.toml b/schema/ambient.toml index 0c8bf88755..421df3e9b1 100644 --- a/schema/ambient.toml +++ b/schema/ambient.toml @@ -1,5 +1,4 @@ [package] -id = "ambient_core" description = "Contains all core components for the Ambient runtime." name = "Core Components" version = "0.3.0-dev" diff --git a/schema/schema/animation.toml b/schema/schema/animation.toml index a39033dc78..6bfaf30a70 100644 --- a/schema/schema/animation.toml +++ b/schema/schema/animation.toml @@ -1,5 +1,4 @@ [package] -id = "animation" name = "Animation" description = "Components relating to animations." content = { type = "Asset", schema = true } diff --git a/schema/schema/app_.toml b/schema/schema/app_.toml index 70c5cd1b8d..1cbeb78c49 100644 --- a/schema/schema/app_.toml +++ b/schema/schema/app_.toml @@ -1,5 +1,4 @@ [package] -id = "app" name = "App" description = "High-level state relevant to the application (including the in-development Editor)." content = { type = "Asset", schema = true } diff --git a/schema/schema/audio.toml b/schema/schema/audio.toml index 534806deef..d7b0c11d3f 100644 --- a/schema/schema/audio.toml +++ b/schema/schema/audio.toml @@ -1,5 +1,4 @@ [package] -id = "audio" name = "Audio" description = "Audio functionality and state." content = { type = "Asset", schema = true } diff --git a/schema/schema/camera.toml b/schema/schema/camera.toml index a037a507b5..e28e44f6b2 100644 --- a/schema/schema/camera.toml +++ b/schema/schema/camera.toml @@ -1,5 +1,4 @@ [package] -id = "camera" name = "Camera" description = "Camera matrices, types, parameters, and more." content = { type = "Asset", schema = true } diff --git a/schema/schema/ecs.toml b/schema/schema/ecs.toml index 8417bfffb3..c2a41fb3e6 100644 --- a/schema/schema/ecs.toml +++ b/schema/schema/ecs.toml @@ -1,5 +1,4 @@ [package] -id = "ecs" name = "Entity Component System" description = "Core components for the ECS and entities." content = { type = "Asset", schema = true } diff --git a/schema/schema/hierarchy.toml b/schema/schema/hierarchy.toml index bde2fb4ad3..5328cd6c68 100644 --- a/schema/schema/hierarchy.toml +++ b/schema/schema/hierarchy.toml @@ -1,5 +1,4 @@ [package] -id = "hierarchy" name = "Hierarchy" description = "Parent/child relationships." content = { type = "Asset", schema = true } diff --git a/schema/schema/input.toml b/schema/schema/input.toml index 762682e93b..897ef6fffc 100644 --- a/schema/schema/input.toml +++ b/schema/schema/input.toml @@ -1,5 +1,4 @@ [package] -id = "input" name = "Input" description = "Mouse, keyboard and controller input." content = { type = "Asset", schema = true } diff --git a/schema/schema/layout.toml b/schema/schema/layout.toml index 20b49021da..4c768438b7 100644 --- a/schema/schema/layout.toml +++ b/schema/schema/layout.toml @@ -1,5 +1,4 @@ [package] -id = "layout" name = "Layout" description = "Layout components such as flow, margins etc." content = { type = "Asset", schema = true } diff --git a/schema/schema/model.toml b/schema/schema/model.toml index 9206e8bd61..d44242010d 100644 --- a/schema/schema/model.toml +++ b/schema/schema/model.toml @@ -1,5 +1,4 @@ [package] -id = "model" name = "Model" description = "Information about models attached to entities." content = { type = "Asset", schema = true } diff --git a/schema/schema/network.toml b/schema/schema/network.toml index 9adacc551b..083cb9236d 100644 --- a/schema/schema/network.toml +++ b/schema/schema/network.toml @@ -1,5 +1,4 @@ [package] -id = "network" name = "Network" description = "Network-related state." content = { type = "Asset", schema = true } diff --git a/schema/schema/package.toml b/schema/schema/package.toml index de7cd55c6a..618ba40271 100644 --- a/schema/schema/package.toml +++ b/schema/schema/package.toml @@ -1,5 +1,4 @@ [package] -id = "package" name = "Package" description = "Package-related state and functionality." content = { type = "Asset", schema = true } diff --git a/schema/schema/physics.toml b/schema/schema/physics.toml index 1a92b972f6..f2c9f5c377 100644 --- a/schema/schema/physics.toml +++ b/schema/schema/physics.toml @@ -1,5 +1,4 @@ [package] -id = "physics" name = "Physics" description = "Physics functionality and state." content = { type = "Asset", schema = true } diff --git a/schema/schema/player.toml b/schema/schema/player.toml index faf67749ae..1bbd7e523d 100644 --- a/schema/schema/player.toml +++ b/schema/schema/player.toml @@ -1,5 +1,4 @@ [package] -id = "player" name = "Player" description = "Components that are attached to player entities." content = { type = "Asset", schema = true } diff --git a/schema/schema/prefab.toml b/schema/schema/prefab.toml index 98dbf85ee1..fe18ff0070 100644 --- a/schema/schema/prefab.toml +++ b/schema/schema/prefab.toml @@ -1,5 +1,4 @@ [package] -id = "prefab" name = "Prefab" description = "Prefab-related state, including loading of prefabs." content = { type = "Asset", schema = true } diff --git a/schema/schema/primitives.toml b/schema/schema/primitives.toml index 3ba27f1115..aec42f49f1 100644 --- a/schema/schema/primitives.toml +++ b/schema/schema/primitives.toml @@ -1,5 +1,4 @@ [package] -id = "primitives" name = "Primitives" description = "Components that create primitive (in the geometric sense) objects from their attached entities." content = { type = "Asset", schema = true } diff --git a/schema/schema/procedurals.toml b/schema/schema/procedurals.toml index efdd83c755..b98ede353c 100644 --- a/schema/schema/procedurals.toml +++ b/schema/schema/procedurals.toml @@ -1,5 +1,4 @@ [package] -id = "procedurals" name = "Procedurals" description = "Procedural asset functionality and related." content = { type = "Asset", schema = true } diff --git a/schema/schema/rect.toml b/schema/schema/rect.toml index 7351f072f4..c95f10962f 100644 --- a/schema/schema/rect.toml +++ b/schema/schema/rect.toml @@ -1,5 +1,4 @@ [package] -id = "rect" name = "Rect" description = "Rounded corners rectangle rendering components, with an optional border." content = { type = "Asset", schema = true } diff --git a/schema/schema/rendering.toml b/schema/schema/rendering.toml index 113852caa0..3d4889321c 100644 --- a/schema/schema/rendering.toml +++ b/schema/schema/rendering.toml @@ -1,5 +1,4 @@ [package] -id = "rendering" name = "Rendering" description = "Rendering-related state, including global rendering parameters and per-entity state." content = { type = "Asset", schema = true } diff --git a/schema/schema/text.toml b/schema/schema/text.toml index ffa1f02956..e950e468e5 100644 --- a/schema/schema/text.toml +++ b/schema/schema/text.toml @@ -1,5 +1,4 @@ [package] -id = "text" name = "Text" description = "Text rendering." content = { type = "Asset", schema = true } diff --git a/schema/schema/transform.toml b/schema/schema/transform.toml index ff31980895..09e6565f28 100644 --- a/schema/schema/transform.toml +++ b/schema/schema/transform.toml @@ -1,5 +1,4 @@ [package] -id = "transform" name = "Transform" description = "Entity transform state (including translation, rotation and scale), as well as other transformations for this entity." content = { type = "Asset", schema = true } diff --git a/schema/schema/ui.toml b/schema/schema/ui.toml index a939b7be94..3d45835822 100644 --- a/schema/schema/ui.toml +++ b/schema/schema/ui.toml @@ -1,5 +1,4 @@ [package] -id = "ui" name = "UI" description = "User interface components" content = { type = "Asset", schema = true } diff --git a/schema/schema/wasm.toml b/schema/schema/wasm.toml index a84284ecad..5abac568e6 100644 --- a/schema/schema/wasm.toml +++ b/schema/schema/wasm.toml @@ -1,5 +1,4 @@ [package] -id = "wasm" name = "WASM" description = "State related to WASM functionality." content = { type = "Asset", schema = true } diff --git a/shared_crates/package/Cargo.toml b/shared_crates/package/Cargo.toml index 04a5d6e0c6..49f01d2620 100644 --- a/shared_crates/package/Cargo.toml +++ b/shared_crates/package/Cargo.toml @@ -24,6 +24,8 @@ url = { workspace = true } chrono = { workspace = true } semver = { workspace = true } rand = { workspace = true } +sha2 = { workspace = true } +data-encoding = { workspace = true } [dev-dependencies] paste = { workspace = true } diff --git a/shared_crates/package/src/manifest.rs b/shared_crates/package/src/manifest.rs index e9812e615d..3c01f18ce2 100644 --- a/shared_crates/package/src/manifest.rs +++ b/shared_crates/package/src/manifest.rs @@ -1,19 +1,19 @@ use std::{collections::HashMap, fmt::Display, path::PathBuf}; use indexmap::IndexMap; -use rand::{seq::SliceRandom, Rng}; +use semver::{Version, VersionReq}; use serde::{Deserialize, Serialize}; +use sha2::Digest; use thiserror::Error; use url::Url; use crate::{ Component, Concept, Enum, ItemPathBuf, Message, PascalCaseIdentifier, SnakeCaseIdentifier, }; -use semver::{Version, VersionReq}; #[derive(Error, Debug, PartialEq)] pub enum ManifestParseError { - #[error("manifest was not valid TOML")] + #[error("manifest was not valid TOML: {0}")] TomlError(#[from] toml::de::Error), #[error("manifest contains a project and/or an ember section; projects/embers have been renamed to packages")] ProjectEmberRenamedToPackageError, @@ -56,36 +56,84 @@ impl Manifest { } } -#[derive(Deserialize, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Default, Serialize)] +#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Default, Serialize)] #[serde(transparent)] +/// A checksummed package ID. Guaranteed to be a valid `SnakeCaseIdentifier` as well. pub struct PackageId(pub(crate) String); +impl<'de> Deserialize<'de> for PackageId { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + PackageId::new(&String::deserialize(deserializer)?).map_err(serde::de::Error::custom) + } +} impl PackageId { + const DATA_LENGTH: usize = 12; + const CHECKSUM_LENGTH: usize = 8; + const TOTAL_LENGTH: usize = Self::DATA_LENGTH + Self::CHECKSUM_LENGTH; + pub fn as_str(&self) -> &str { &self.0 } + /// Attempts to create a new package ID from a string. + pub fn new(id: &str) -> Result { + Self::validate(id)?; + Ok(Self(id.to_string())) + } + /// Generates a new package ID. - // TODO: suffix with checksum pub fn generate() -> Self { - const NUMERALS: [u8; 10] = [b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9']; - const ALPHABET: [u8; 26] = [ - b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n', - b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', b'z', - ]; - - let mut rng = rand::thread_rng(); - let mut output = vec![0u8; 32]; - output[0] = *ALPHABET.choose(&mut rng).unwrap(); - for i in 1..output.len() { - let idx = rng.gen_range(0..(NUMERALS.len() + ALPHABET.len())); - output[i] = if idx < NUMERALS.len() { - NUMERALS[idx] - } else { - ALPHABET[idx - NUMERALS.len()] - }; + // TODO: see if there's a more intelligent way to ensure the first character + // is always alphabetic + loop { + let data: [u8; Self::DATA_LENGTH] = rand::random(); + let checksum: [u8; Self::CHECKSUM_LENGTH] = sha2::Sha256::digest(&data) + [0..Self::CHECKSUM_LENGTH] + .try_into() + .unwrap(); + + let mut bytes = [0u8; Self::TOTAL_LENGTH]; + bytes[0..Self::DATA_LENGTH].copy_from_slice(&data); + bytes[Self::DATA_LENGTH..].copy_from_slice(&checksum); + + let output = data_encoding::BASE32_NOPAD + .encode(&bytes) + .to_ascii_lowercase(); + + if output.chars().next().unwrap().is_alphabetic() { + return Self(output); + } + } + } + + /// Validate that a package ID is correct. + pub fn validate(id: &str) -> Result<(), String> { + let cmd = + "Use `ambient package regenerate-id` to regenerate the package ID with the new format."; + + let bytes = data_encoding::BASE32_NOPAD + .decode(id.to_ascii_uppercase().as_bytes()) + .map_err(|e| { + format!( + "Package ID contained invalid characters: {}. {cmd}", + e.to_string() + ) + })?; + + let data = &bytes[0..Self::DATA_LENGTH]; + let checksum = &bytes[Self::DATA_LENGTH..]; + + let expected_checksum = &sha2::Sha256::digest(data)[0..Self::CHECKSUM_LENGTH]; + if checksum != expected_checksum { + return Err(format!( + "Package ID contained invalid checksum: expected {:?}, got {:?}. {cmd}", + expected_checksum, checksum + )); } - Self(String::from_utf8(output).unwrap()) + Ok(()) } } impl Display for PackageId { @@ -93,10 +141,17 @@ impl Display for PackageId { self.0.fmt(f) } } +impl From for SnakeCaseIdentifier { + fn from(id: PackageId) -> Self { + SnakeCaseIdentifier(id.0) + } +} #[derive(Deserialize, Clone, Debug, PartialEq, Serialize)] pub struct Package { - pub id: PackageId, + /// The ID can be optional if and only if the package is `ambient_core` or an include. + #[serde(default)] + pub id: Option, pub name: String, pub version: Version, pub description: Option, @@ -251,7 +306,7 @@ mod tests { fn can_parse_minimal_toml() { const TOML: &str = r#" [package] - id = "test" + id = "lktsfudbjw2qikhyumt573ozxhadkiwm" name = "Test" version = "0.0.1" content = { type = "Playable" } @@ -261,7 +316,7 @@ mod tests { Manifest::parse(TOML), Ok(Manifest { package: Package { - id: PackageId("test".to_string()), + id: Some(PackageId("lktsfudbjw2qikhyumt573ozxhadkiwm".to_string())), name: "Test".to_string(), version: Version::parse("0.0.1").unwrap(), ..Default::default() @@ -275,7 +330,7 @@ mod tests { fn will_fail_on_legacy_project_toml() { const TOML: &str = r#" [project] - id = "test" + id = "lktsfudbjw2qikhyumt573ozxhadkiwm" name = "Test" version = "0.0.1" "#; @@ -290,7 +345,7 @@ mod tests { fn can_parse_tictactoe_toml() { const TOML: &str = r#" [package] - id = "tictactoe" + id = "lktsfudbjw2qikhyumt573ozxhadkiwm" name = "Tic Tac Toe" version = "0.0.1" content = { type = "Playable" } @@ -309,7 +364,7 @@ mod tests { Manifest::parse(TOML), Ok(Manifest { package: Package { - id: PackageId("tictactoe".to_string()), + id: Some(PackageId("lktsfudbjw2qikhyumt573ozxhadkiwm".to_string())), name: "Tic Tac Toe".to_string(), version: Version::parse("0.0.1").unwrap(), ..Default::default() @@ -353,7 +408,7 @@ mod tests { fn can_parse_rust_build_settings() { const TOML: &str = r#" [package] - id = "tictactoe" + id = "lktsfudbjw2qikhyumt573ozxhadkiwm" name = "Tic Tac Toe" version = "0.0.1" content = { type = "Playable" } @@ -367,7 +422,7 @@ mod tests { Manifest::parse(TOML), Ok(Manifest { package: Package { - id: PackageId("tictactoe".to_string()), + id: Some(PackageId("lktsfudbjw2qikhyumt573ozxhadkiwm".to_string())), name: "Tic Tac Toe".to_string(), version: Version::parse("0.0.1").unwrap(), ambient_version: Some( @@ -391,7 +446,7 @@ mod tests { const TOML: &str = r#" [package] - id = "my_package" + id = "lktsfudbjw2qikhyumt573ozxhadkiwm" name = "My Package" version = "0.0.1" content = { type = "Playable" } @@ -421,7 +476,7 @@ mod tests { manifest, Manifest { package: Package { - id: PackageId("my_package".to_string()), + id: Some(PackageId("lktsfudbjw2qikhyumt573ozxhadkiwm".to_string())), name: "My Package".to_string(), version: Version::parse("0.0.1").unwrap(), ..Default::default() @@ -557,7 +612,7 @@ mod tests { fn can_parse_enums() { const TOML: &str = r#" [package] - id = "tictactoe" + id = "lktsfudbjw2qikhyumt573ozxhadkiwm" name = "Tic Tac Toe" version = "0.0.1" content = { type = "Playable" } @@ -573,7 +628,7 @@ mod tests { Manifest::parse(TOML), Ok(Manifest { package: Package { - id: PackageId("tictactoe".to_string()), + id: Some(PackageId("lktsfudbjw2qikhyumt573ozxhadkiwm".to_string())), name: "Tic Tac Toe".to_string(), version: Version::parse("0.0.1").unwrap(), ..Default::default() @@ -602,7 +657,7 @@ mod tests { fn can_parse_container_types() { const TOML: &str = r#" [package] - id = "test" + id = "lktsfudbjw2qikhyumt573ozxhadkiwm" name = "Test" version = "0.0.1" content = { type = "Playable" } @@ -618,7 +673,7 @@ mod tests { Manifest::parse(TOML), Ok(Manifest { package: Package { - id: PackageId("test".to_string()), + id: Some(PackageId("lktsfudbjw2qikhyumt573ozxhadkiwm".to_string())), name: "Test".to_string(), version: Version::parse("0.0.1").unwrap(), ..Default::default() @@ -679,7 +734,7 @@ mod tests { fn can_parse_dependencies() { const TOML: &str = r#" [package] - id = "dependencies" + id = "lktsfudbjw2qikhyumt573ozxhadkiwm" name = "dependencies" version = "0.0.1" content = { type = "Playable" } @@ -697,7 +752,7 @@ mod tests { Manifest::parse(TOML), Ok(Manifest { package: Package { - id: PackageId("dependencies".to_string()), + id: Some(PackageId("lktsfudbjw2qikhyumt573ozxhadkiwm".to_string())), name: "dependencies".to_string(), version: Version::parse("0.0.1").unwrap(), ..Default::default() diff --git a/shared_crates/package_semantic/src/lib.rs b/shared_crates/package_semantic/src/lib.rs index 2c290b1837..62f0ea2165 100644 --- a/shared_crates/package_semantic/src/lib.rs +++ b/shared_crates/package_semantic/src/lib.rs @@ -9,7 +9,7 @@ use anyhow::Context as AnyhowContext; use async_recursion::async_recursion; use ambient_package::{ - BuildMetadata, ComponentType, Identifier, ItemPath, ItemPathBuf, Manifest, PackageId, + BuildMetadata, ComponentType, Identifier, ItemPath, ItemPathBuf, Manifest, PascalCaseIdentifier, SnakeCaseIdentifier, }; use ambient_shared_types::primitive_component_definitions; @@ -61,6 +61,10 @@ pub fn schema() -> &'static Schema { #[derive(Error, Debug)] pub enum PackageAddError { + #[error( + "The manifest in {include_source} does not have an ID, and no ID override was provided" + )] + MissingId { include_source: RetrievableFile }, #[error("Failed to parse manifest from `{manifest_path}`")] ManifestParseError { manifest_path: RetrievableFile, @@ -144,7 +148,7 @@ pub struct Semantic { pub root_scope_id: ItemId, pub packages: HashMap>, /// Used to determine if there are any existing packages with this ID - pub id_to_locator: HashMap, + pub id_to_locator: HashMap, pub ambient_package_id: ItemId, pub standard_definitions: StandardDefinitions, ignore_local_dependencies: bool, @@ -190,7 +194,23 @@ impl Semantic { } })?; - let locator = PackageLocator::from_manifest(&manifest, retrievable_manifest.clone()); + // If and only if this is the root Ambient core manifest, override its ID. + // Otherwise, leave it alone. + let id_override = match &retrievable_manifest { + RetrievableFile::Ambient(path) if path == Path::new("ambient.toml") => Some( + Identifier::from(SnakeCaseIdentifier::new("ambient_core").unwrap()), + ), + _ => None, + }; + + let locator = PackageLocator::from_manifest( + &manifest, + retrievable_manifest.clone(), + id_override.clone(), + ) + .ok_or_else(|| PackageAddError::MissingId { + include_source: retrievable_manifest.clone(), + })?; if let Some(id) = self.packages.get(&locator) { return Ok(*id); @@ -221,7 +241,12 @@ impl Semantic { .transpose()?; let scope_id = self - .add_scope_from_manifest_with_includes(None, &manifest, retrievable_manifest.clone()) + .add_scope_from_manifest_with_includes( + None, + &manifest, + retrievable_manifest.clone(), + id_override, + ) .await?; let manifest_dependencies = manifest.dependencies.clone(); @@ -420,10 +445,15 @@ impl Semantic { parent_id: Option>, manifest: &Manifest, source: RetrievableFile, + id_override: Option, ) -> Result, PackageAddError> { let includes = manifest.includes.clone(); - let scope_id = - self.add_scope_from_manifest_without_includes(parent_id, manifest, source.clone())?; + let scope_id = self.add_scope_from_manifest_without_includes( + parent_id, + manifest, + source.clone(), + id_override, + )?; let mut include_names: Vec<_> = includes.keys().collect(); include_names.sort(); @@ -452,6 +482,7 @@ impl Semantic { Some(scope_id), &include_manifest, include_source, + Some(include_name.clone().into()), ) .await?; @@ -469,6 +500,7 @@ impl Semantic { parent_id: Option>, manifest: &Manifest, source: RetrievableFile, + id_override: Option, ) -> Result, PackageAddError> { let item_source = match source { RetrievableFile::Ambient(_) => ItemSource::Ambient, @@ -476,7 +508,15 @@ impl Semantic { }; let scope_id = self.items.add(Scope::new(ItemData { parent_id, - id: manifest.package.id.clone().into(), + id: manifest + .package + .id + .clone() + .map(Identifier::from) + .or(id_override) + .ok_or_else(|| PackageAddError::MissingId { + include_source: source.clone(), + })?, source: item_source, })); diff --git a/shared_crates/package_semantic/src/package.rs b/shared_crates/package_semantic/src/package.rs index cc8e0ab8c1..6b256bbc52 100644 --- a/shared_crates/package_semantic/src/package.rs +++ b/shared_crates/package_semantic/src/package.rs @@ -4,7 +4,7 @@ use std::{ path::{Path, PathBuf}, }; -use ambient_package::{BuildMetadata, Manifest, PackageId, SnakeCaseIdentifier}; +use ambient_package::{BuildMetadata, Identifier, Manifest, SnakeCaseIdentifier}; use ambient_std::path; use thiserror::Error; use url::Url; @@ -18,17 +18,26 @@ use semver::Version; #[derive(Clone, PartialEq, Debug, Eq, Hash)] pub struct PackageLocator { - pub id: PackageId, + pub id: Identifier, pub version: Version, pub source: RetrievableFile, } impl PackageLocator { - pub fn from_manifest(manifest: &Manifest, source: RetrievableFile) -> Self { - Self { - id: manifest.package.id.clone(), + pub fn from_manifest( + manifest: &Manifest, + source: RetrievableFile, + id_override: Option, + ) -> Option { + Some(Self { + id: manifest + .package + .id + .clone() + .map(Identifier::from) + .or(id_override)?, version: manifest.package.version.clone(), source, - } + }) } } impl Display for PackageLocator { diff --git a/web/Cargo.lock b/web/Cargo.lock index 5936572457..cace08343f 100644 --- a/web/Cargo.lock +++ b/web/Cargo.lock @@ -668,6 +668,7 @@ dependencies = [ "ambient_shared_types", "chrono", "convert_case 0.6.0", + "data-encoding", "indexmap 2.0.0", "once_cell", "proc-macro2", @@ -675,6 +676,7 @@ dependencies = [ "rand 0.8.5", "semver 1.0.18", "serde", + "sha2", "syn 1.0.109", "thiserror", "toml", @@ -1488,6 +1490,15 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "block-sys" version = "0.1.0-beta.1" @@ -1924,6 +1935,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "cpufeatures" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +dependencies = [ + "libc", +] + [[package]] name = "cranelift-bforest" version = "0.101.0" @@ -2090,6 +2110,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "d3d12" version = "0.6.0" @@ -2200,6 +2230,16 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "dioxus" version = "0.3.2" @@ -5658,6 +5698,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" +[[package]] +name = "sha2" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.4"