From 3e6a444d4c90422169bc6eec5ef81cdb95da3883 Mon Sep 17 00:00:00 2001 From: Stephen Hodgson Date: Sat, 10 Jun 2023 23:17:22 -0400 Subject: [PATCH] com.rest.blockadelabs 1.0.0-preview.2 (#2) --- .gitignore | 1 + BlockadeLabs/Assets/Demo/SkyboxDemo.unity | 10 +- .../Documentation~/README.md | 117 +++++++++++++++++- .../images/create-scriptable-object.png | Bin 0 -> 43116 bytes .../Runtime/Skyboxes/SkyboxEndpoint.cs | 17 +-- .../Tests/TestFixture_00_Skyboxes.cs | 21 ++-- .../com.rest.blockadelabs/package.json | 2 +- README.md | 117 +++++++++++++++++- 8 files changed, 248 insertions(+), 37 deletions(-) create mode 100644 BlockadeLabs/Packages/com.rest.blockadelabs/Documentation~/images/create-scriptable-object.png diff --git a/.gitignore b/.gitignore index 494b95a..1394e7b 100644 --- a/.gitignore +++ b/.gitignore @@ -86,3 +86,4 @@ BlockadeLabs/Assets/Resources BlockadeLabs/Assets/Resources.meta BlockadeLabs/Assets/Plugins BlockadeLabs/Assets/Plugins.meta +BlockadeLabs/ProjectSettings/SceneTemplateSettings.json diff --git a/BlockadeLabs/Assets/Demo/SkyboxDemo.unity b/BlockadeLabs/Assets/Demo/SkyboxDemo.unity index 7971a19..975947a 100644 --- a/BlockadeLabs/Assets/Demo/SkyboxDemo.unity +++ b/BlockadeLabs/Assets/Demo/SkyboxDemo.unity @@ -212,14 +212,14 @@ MonoBehaviour: m_VerticalScrollbarEventHandler: {fileID: 0} m_LayoutGroup: {fileID: 0} m_ScrollSensitivity: 1 - m_ContentType: 4 + m_ContentType: 0 m_InputType: 0 m_AsteriskChar: 42 - m_KeyboardType: 1 - m_LineType: 0 + m_KeyboardType: 0 + m_LineType: 1 m_HideMobileInput: 0 m_HideSoftKeyboard: 0 - m_CharacterValidation: 4 + m_CharacterValidation: 0 m_RegexValue: m_GlobalPointSize: 24 m_CharacterLimit: 0 @@ -2137,7 +2137,7 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_enableWordWrapping: 0 + m_enableWordWrapping: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} diff --git a/BlockadeLabs/Packages/com.rest.blockadelabs/Documentation~/README.md b/BlockadeLabs/Packages/com.rest.blockadelabs/Documentation~/README.md index 7f30b21..447c6d1 100644 --- a/BlockadeLabs/Packages/com.rest.blockadelabs/Documentation~/README.md +++ b/BlockadeLabs/Packages/com.rest.blockadelabs/Documentation~/README.md @@ -2,10 +2,18 @@ [![openupm](https://img.shields.io/npm/v/com.rest.blockadelabs?label=openupm®istry_uri=https://package.openupm.com)](https://openupm.com/packages/com.rest.blockadelabs/) -A BlockadeLabs package for the [Unity](https://unity.com/) Game Engine. +A non-official [BlockadeLabs](https://www.blockadelabs.com/) Skybox AI RESTful client for the [Unity](https://unity.com/) Game Engine. + +I am not affiliated with BlockadeLabs and an account with api access is required. + +***All copyrights, trademarks, logos, and assets are the property of their respective owners.*** ## Installing +Requires Unity 2021.3 LTS or higher. + +The recommended installation method is though the unity package manager and [OpenUPM](https://openupm.com/packages/com.openai.unity). + ### Via Unity Package Manager and OpenUPM - Open your Unity project settings @@ -15,7 +23,7 @@ A BlockadeLabs package for the [Unity](https://unity.com/) Game Engine. - Name: `OpenUPM` - URL: `https://package.openupm.com` - Scope(s): - - `com.rest` + - `com.rest.blockadelabs` - `com.utilities` - Open the Unity Package Manager window - Change the Registry from Unity to `My Registries` @@ -25,11 +33,112 @@ A BlockadeLabs package for the [Unity](https://unity.com/) Game Engine. - Open your Unity Package Manager - Add package from git url: `https://github.com/RageAgainstThePixel/com.rest.blockadelabs.git#upm` + > Note: this repo has dependencies on other repositories! You are responsible for adding these on your own. + - [com.utilities.async](https://github.com/RageAgainstThePixel/com.utilities.async) + - [com.utilities.rest](https://github.com/RageAgainstThePixel/com.utilities.rest) ## Documentation -### Project Setup +### Table of Contents + +- [Authentication](#authentication) +- [Skyboxes](#skyboxes) + - [Get Skybox Styles](#get-skybox-styles) + - [Generate Skybox](#generate-skybox) + - [Get Skybox by Id](get-skybox) + +### Authentication + +There are 4 ways to provide your API keys, in order of precedence: + +1. [Pass keys directly with constructor](#pass-keys-directly-with-constructor) +2. [Unity Scriptable Object](#unity-scriptable-object) +3. [Load key from configuration file](#load-key-from-configuration-file) +4. [Use System Environment Variables](#use-system-environment-variables) + +#### Pass keys directly with constructor + +```csharp +var api = new BlockadeLabsClient("yourApiKey"); +``` + +Or create a `BlockadeLabsAuthentication` object manually + +```csharp +var api = new BlockadeLabsClient(new BlockadeLabsAuthentication("yourApiKey")); +``` + +#### Unity Scriptable Object + +You can save the key directly into a scriptable object that is located in the `Assets/Resources` folder. + +You can create a new one by using the context menu of the project pane and creating a new `BlockadeLabsConfiguration` scriptable object. + +![Create new BlockadeLabsConfiguration](images/create-scriptable-object.png) + +#### Load key from configuration file + +Attempts to load api keys from a configuration file, by default `.blockadelabs` in the current directory, optionally traversing up the directory tree or in the user's home directory. + +To create a configuration file, create a new text file named `.blockadelabs` and containing the line: + +##### Json format + +```json +{ + "apiKey": "yourApiKey", +} +``` + +You can also load the file directly with known path by calling a static method in Authentication: + +```csharp +var api = new BlockadeLabsClient(BlockadeLabsAuthentication.Default.LoadFromDirectory("your/path/to/.blockadelabs"));; +``` + +#### Use System Environment Variables + +Use your system's environment variables specify an api key to use. + +- Use `BLOCKADE_LABS_API_KEY` for your api key. + +```csharp +var api = new BlockadeLabsClient(BlockadeLabsAuthentication.Default.LoadFromEnvironment()); +``` + +### Skyboxes + +#### [Get Skybox Styles](https://blockade.cloudshell.run/redoc#tag/skybox/operation/Get_Skybox_Styles_api_v1_skybox_styles_get) + +Returns the list of predefined styles that can influence the overall aesthetic of your skybox generation. + +```csharp +var api = new BlockadeLabsClient(); +var skyboxStyles = await api.SkyboxEndpoint.GetSkyboxStylesAsync(); + +foreach (var skyboxStyle in skyboxStyles) +{ + Debug.Log($"{skyboxStyle.Name}"); +} +``` + +#### [Generate Skybox](https://blockade.cloudshell.run/redoc#tag/skybox/operation/Generate_Skybox_api_v1_skybox_generate_post) + +Generate a skybox image + +```csharp +var api = new BlockadeLabsClient(); +var request = new SkyboxRequest("underwater", depth: true); +var skyboxInfo = await api.SkyboxEndpoint.GenerateSkyboxAsync(request); +skyboxMaterial.mainTexture = skyboxInfo.MainTexture; +skyboxMaterial.depthTexture = skyboxInfo.DepthTexture; +``` + +#### [Get Skybox](https://blockade.cloudshell.run/redoc#tag/skybox/operation/Get_Skybox_By_Id_api_v1_skybox_info__id__get) + +Returns the skybox metadata for the given skybox id. ```csharp -// TODO +var skyboxInfo = await api.SkyboxEndpoint.GetSkyboxInfoAsync("skybox-id"); +Debug.Log($"Skybox: {result.Id} | {result.MainTextureUrl}"); ``` diff --git a/BlockadeLabs/Packages/com.rest.blockadelabs/Documentation~/images/create-scriptable-object.png b/BlockadeLabs/Packages/com.rest.blockadelabs/Documentation~/images/create-scriptable-object.png new file mode 100644 index 0000000000000000000000000000000000000000..483b1221d8777b57ce8acdf8f1a4eb957f062f94 GIT binary patch literal 43116 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 "skybox"; @@ -84,7 +69,7 @@ public async Task GetSkyboxInfoAsync(int id, CancellationToken cance { var response = await Rest.GetAsync(GetUrl($"/info/{id}"), parameters: new RestParameters(client.DefaultRequestHeaders), cancellationToken); response.Validate(); - return JsonConvert.DeserializeObject(response.Body, client.JsonSerializationOptions).Request; + return JsonConvert.DeserializeObject(response.Body, client.JsonSerializationOptions); } } } diff --git a/BlockadeLabs/Packages/com.rest.blockadelabs/Tests/TestFixture_00_Skyboxes.cs b/BlockadeLabs/Packages/com.rest.blockadelabs/Tests/TestFixture_00_Skyboxes.cs index 329f529..6747b56 100644 --- a/BlockadeLabs/Packages/com.rest.blockadelabs/Tests/TestFixture_00_Skyboxes.cs +++ b/BlockadeLabs/Packages/com.rest.blockadelabs/Tests/TestFixture_00_Skyboxes.cs @@ -12,10 +12,10 @@ public async Task Test_01_GetSkyboxStyles() { var api = new BlockadeLabsClient(); Assert.IsNotNull(api.SkyboxEndpoint); - var result = await api.SkyboxEndpoint.GetSkyboxStylesAsync(); - Assert.IsNotNull(result); + var skyboxStyles = await api.SkyboxEndpoint.GetSkyboxStylesAsync(); + Assert.IsNotNull(skyboxStyles); - foreach (var skyboxStyle in result) + foreach (var skyboxStyle in skyboxStyles) { Debug.Log($"{skyboxStyle.Name}"); } @@ -27,18 +27,25 @@ public async Task Test_02_GenerateSkybox() var api = new BlockadeLabsClient(); Assert.IsNotNull(api.SkyboxEndpoint); - var request = new SkyboxRequest("underwater"/*, depth: true*/); + var request = new SkyboxRequest("underwater", depth: true); var skyboxInfo = await api.SkyboxEndpoint.GenerateSkyboxAsync(request); Assert.IsNotNull(skyboxInfo); + Debug.Log($"Successfully created skybox: {skyboxInfo.Id}"); Debug.Log(skyboxInfo.MainTextureUrl); Assert.IsNotNull(skyboxInfo.MainTexture); Debug.Log(skyboxInfo.DepthTextureUrl); - //Assert.IsNotNull(skyboxInfo.DepthTexture); + Assert.IsNotNull(skyboxInfo.DepthTexture); + } + + [Test] + public async Task Test_03_GetSkyboxInfo() + { + var api = new BlockadeLabsClient(); + Assert.IsNotNull(api.SkyboxEndpoint); - var result = await api.SkyboxEndpoint.GetSkyboxInfoAsync(skyboxInfo.Id); + var result = await api.SkyboxEndpoint.GetSkyboxInfoAsync(5719637); Assert.IsNotNull(result); Debug.Log($"Skybox: {result.Id} | {result.MainTextureUrl}"); - Assert.IsTrue(skyboxInfo.Id == result.Id); } } } diff --git a/BlockadeLabs/Packages/com.rest.blockadelabs/package.json b/BlockadeLabs/Packages/com.rest.blockadelabs/package.json index 99554b9..b881001 100644 --- a/BlockadeLabs/Packages/com.rest.blockadelabs/package.json +++ b/BlockadeLabs/Packages/com.rest.blockadelabs/package.json @@ -3,7 +3,7 @@ "displayName": "BlockadeLabs", "description": "A Non-Official Blockade Labs Rest Client for Unity (UPM)", "keywords": [], - "version": "1.0.0-preview.1", + "version": "1.0.0-preview.2", "unity": "2021.3", "documentationUrl": "https://github.com/RageAgainstThePixel/com.rest.blockadelabs#documentation", "changelogUrl": "https://github.com/RageAgainstThePixel/com.rest.blockadelabs/releases", diff --git a/README.md b/README.md index dcd5323..9368257 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,18 @@ [![openupm](https://img.shields.io/npm/v/com.rest.blockadelabs?label=openupm®istry_uri=https://package.openupm.com)](https://openupm.com/packages/com.rest.blockadelabs/) -A BlockadeLabs package for the [Unity](https://unity.com/) Game Engine. +A non-official [BlockadeLabs](https://www.blockadelabs.com/) Skybox AI RESTful client for the [Unity](https://unity.com/) Game Engine. + +I am not affiliated with BlockadeLabs and an account with api access is required. + +***All copyrights, trademarks, logos, and assets are the property of their respective owners.*** ## Installing +Requires Unity 2021.3 LTS or higher. + +The recommended installation method is though the unity package manager and [OpenUPM](https://openupm.com/packages/com.openai.unity). + ### Via Unity Package Manager and OpenUPM - Open your Unity project settings @@ -15,7 +23,7 @@ A BlockadeLabs package for the [Unity](https://unity.com/) Game Engine. - Name: `OpenUPM` - URL: `https://package.openupm.com` - Scope(s): - - `com.rest` + - `com.rest.blockadelabs` - `com.utilities` - Open the Unity Package Manager window - Change the Registry from Unity to `My Registries` @@ -25,11 +33,112 @@ A BlockadeLabs package for the [Unity](https://unity.com/) Game Engine. - Open your Unity Package Manager - Add package from git url: `https://github.com/RageAgainstThePixel/com.rest.blockadelabs.git#upm` + > Note: this repo has dependencies on other repositories! You are responsible for adding these on your own. + - [com.utilities.async](https://github.com/RageAgainstThePixel/com.utilities.async) + - [com.utilities.rest](https://github.com/RageAgainstThePixel/com.utilities.rest) ## Documentation -### Project Setup +### Table of Contents + +- [Authentication](#authentication) +- [Skyboxes](#skyboxes) + - [Get Skybox Styles](#get-skybox-styles) + - [Generate Skybox](#generate-skybox) + - [Get Skybox by Id](get-skybox) + +### Authentication + +There are 4 ways to provide your API keys, in order of precedence: + +1. [Pass keys directly with constructor](#pass-keys-directly-with-constructor) +2. [Unity Scriptable Object](#unity-scriptable-object) +3. [Load key from configuration file](#load-key-from-configuration-file) +4. [Use System Environment Variables](#use-system-environment-variables) + +#### Pass keys directly with constructor + +```csharp +var api = new BlockadeLabsClient("yourApiKey"); +``` + +Or create a `BlockadeLabsAuthentication` object manually + +```csharp +var api = new BlockadeLabsClient(new BlockadeLabsAuthentication("yourApiKey")); +``` + +#### Unity Scriptable Object + +You can save the key directly into a scriptable object that is located in the `Assets/Resources` folder. + +You can create a new one by using the context menu of the project pane and creating a new `BlockadeLabsConfiguration` scriptable object. + +![Create new BlockadeLabsConfiguration](BlockadeLabs/Packages/com.rest.blockadelabs/Documentation~/images/create-scriptable-object.png) + +#### Load key from configuration file + +Attempts to load api keys from a configuration file, by default `.blockadelabs` in the current directory, optionally traversing up the directory tree or in the user's home directory. + +To create a configuration file, create a new text file named `.blockadelabs` and containing the line: + +##### Json format + +```json +{ + "apiKey": "yourApiKey", +} +``` + +You can also load the file directly with known path by calling a static method in Authentication: + +```csharp +var api = new BlockadeLabsClient(BlockadeLabsAuthentication.Default.LoadFromDirectory("your/path/to/.blockadelabs"));; +``` + +#### Use System Environment Variables + +Use your system's environment variables specify an api key to use. + +- Use `BLOCKADE_LABS_API_KEY` for your api key. + +```csharp +var api = new BlockadeLabsClient(BlockadeLabsAuthentication.Default.LoadFromEnvironment()); +``` + +### Skyboxes + +#### [Get Skybox Styles](https://blockade.cloudshell.run/redoc#tag/skybox/operation/Get_Skybox_Styles_api_v1_skybox_styles_get) + +Returns the list of predefined styles that can influence the overall aesthetic of your skybox generation. + +```csharp +var api = new BlockadeLabsClient(); +var skyboxStyles = await api.SkyboxEndpoint.GetSkyboxStylesAsync(); + +foreach (var skyboxStyle in skyboxStyles) +{ + Debug.Log($"{skyboxStyle.Name}"); +} +``` + +#### [Generate Skybox](https://blockade.cloudshell.run/redoc#tag/skybox/operation/Generate_Skybox_api_v1_skybox_generate_post) + +Generate a skybox image + +```csharp +var api = new BlockadeLabsClient(); +var request = new SkyboxRequest("underwater", depth: true); +var skyboxInfo = await api.SkyboxEndpoint.GenerateSkyboxAsync(request); +skyboxMaterial.mainTexture = skyboxInfo.MainTexture; +skyboxMaterial.depthTexture = skyboxInfo.DepthTexture; +``` + +#### [Get Skybox](https://blockade.cloudshell.run/redoc#tag/skybox/operation/Get_Skybox_By_Id_api_v1_skybox_info__id__get) + +Returns the skybox metadata for the given skybox id. ```csharp -// TODO +var skyboxInfo = await api.SkyboxEndpoint.GetSkyboxInfoAsync("skybox-id"); +Debug.Log($"Skybox: {result.Id} | {result.MainTextureUrl}"); ```